docassemble.AssemblyLine 3.0.1__tar.gz → 3.1.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.
- {docassemble_assemblyline-3.0.1/docassemble.AssemblyLine.egg-info → docassemble_assemblyline-3.1.0}/PKG-INFO +1 -1
- docassemble_assemblyline-3.1.0/docassemble/AssemblyLine/__init__.py +1 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/al_general.py +310 -118
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/questions/interview_list.yml +16 -1
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/sessions.py +90 -62
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/test_al_general.py +3 -3
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0/docassemble.AssemblyLine.egg-info}/PKG-INFO +1 -1
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/setup.py +1 -1
- docassemble_assemblyline-3.0.1/docassemble/AssemblyLine/__init__.py +0 -1
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/LICENSE +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/MANIFEST.in +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/README.md +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/al_courts.py +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/al_document.py +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/questions/al_code.yml +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/questions/al_document.yml +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/questions/al_language.yml +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/questions/al_package.yml +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/questions/al_package_unstyled.yml +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/questions/al_question_test.yml +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/questions/al_reminders.yml +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/questions/al_saved_sessions.yml +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/questions/al_saved_sessions_store.yml +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/questions/al_settings.yml +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/questions/al_terms_of_use.yml +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/questions/al_visual.yml +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/questions/assembly_line.yml +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/questions/assembly_line_unstyled.yml +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/questions/demo_search_sessions.yml +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/questions/feedback.yml +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/questions/ql_baseline.yml +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/questions/ql_catchall.yml +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/questions/reserved_words.yml +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/questions/test_al_table_document.yml +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/questions/test_aladdendum.yml +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/questions/test_alcourts.yml +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/questions/test_aldocument.yml +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/questions/test_alexhibit.yml +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/questions/test_alexhibit_maxsize.yml +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/questions/test_bundle_parity.yml +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/questions/test_familiar_disambiguation.yml +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/questions/test_question_library.yml +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/sources/README.md +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/sources/es-words.yml +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/sources/languages.yml +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/sources/test_aldocument.feature +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/sources/test_alexhibit_docx_1.docx +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/sources/test_alexhibit_jpg_1.jpg +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/sources/test_alexhibit_pdf_1.pdf +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/sources/test_alexhibit_png_1.png +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/sources/test_question_library.feature +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/sources/translation_es.xlsx +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/sources/translation_ht.xlsx +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/sources/translation_pt.xlsx +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/static/README.md +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/static/al_audio.css +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/static/al_audio.js +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/static/aldocument.css +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/static/aldocument.js +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/static/interview_list.css +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/static/limit_upload_size.js +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/static/lt1-pullout-10-getting-organized.pdf +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/static/ma_logo.png +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/static/placeholder.png +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/static/seal.jpg +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/static/styles.css +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/templates/README.md +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/templates/al_basic_addendum.docx +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/templates/exhibit_cover_sheet.docx +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/templates/exhibit_table_of_contents.docx +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/templates/general_cover_sheet.docx +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/templates/sample_word_template.docx +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/templates/test_aldocument_docx_1.docx +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/data/templates/test_aldocument_pdf_1.pdf +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/language.py +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/project_maintenance.py +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/py.typed +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/requirements.txt +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/test_al_document.py +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/test_language.py +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/__init__.py +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble.AssemblyLine.egg-info/SOURCES.txt +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble.AssemblyLine.egg-info/dependency_links.txt +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble.AssemblyLine.egg-info/namespace_packages.txt +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble.AssemblyLine.egg-info/not-zip-safe +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble.AssemblyLine.egg-info/requires.txt +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble.AssemblyLine.egg-info/top_level.txt +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/pyproject.toml +0 -0
- {docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/setup.cfg +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = '3.1.0'
|
|
@@ -804,6 +804,46 @@ class ALPeopleList(DAList):
|
|
|
804
804
|
and_string=and_string,
|
|
805
805
|
)
|
|
806
806
|
|
|
807
|
+
def pronoun_reflexive(self, **kwargs) -> str:
|
|
808
|
+
"""Returns the appropriate reflexive pronoun for the list of people, depending
|
|
809
|
+
on the `person` keyword argument and the number of items in the list.
|
|
810
|
+
|
|
811
|
+
If the list is singular, return the reflexive pronoun for the first item in the list.
|
|
812
|
+
If it is plural, return the appropriate plural reflexive pronoun (e.g., "themselves")
|
|
813
|
+
|
|
814
|
+
Args:
|
|
815
|
+
**kwargs: Additional keyword arguments that are defined [upstream](https://docassemble.org/docs/objects.html#language%20methods).
|
|
816
|
+
- person (Optional[[Union[str,int]]): Whether to use a first, second, or third person pronoun. Can be one of 1/"1p", 2/"2p", or 3/"3p" (default is 3). See [upstream](https://docassemble.org/docs/objects.html#language%20methods) documentation for more information.
|
|
817
|
+
- default (Optional[str]): The default word to use if the pronoun is not defined, e.g. "the agent". If not defined, the default term is the user's name.
|
|
818
|
+
|
|
819
|
+
Returns:
|
|
820
|
+
str: The reflexive pronoun for the list.
|
|
821
|
+
"""
|
|
822
|
+
person = str(kwargs.get("person", self.get_point_of_view()))
|
|
823
|
+
|
|
824
|
+
if self.number_gathered() > 1:
|
|
825
|
+
if person in ("1", "1p", "2", "2p"):
|
|
826
|
+
if person in ("1", "1p"):
|
|
827
|
+
output = word("ourselves")
|
|
828
|
+
elif person in ("2", "2p"):
|
|
829
|
+
output = word("yourselves")
|
|
830
|
+
else:
|
|
831
|
+
output = word("themselves")
|
|
832
|
+
|
|
833
|
+
elif self.number_gathered() == 1:
|
|
834
|
+
if isinstance(self[0], ALIndividual) and hasattr(
|
|
835
|
+
self[0], "pronoun_reflexive"
|
|
836
|
+
):
|
|
837
|
+
output = self[0].pronoun_reflexive(**kwargs)
|
|
838
|
+
else:
|
|
839
|
+
output = word("itself")
|
|
840
|
+
else:
|
|
841
|
+
output = word("themselves")
|
|
842
|
+
|
|
843
|
+
if kwargs.get("capitalize"):
|
|
844
|
+
return output.capitalize()
|
|
845
|
+
return output
|
|
846
|
+
|
|
807
847
|
|
|
808
848
|
class ALIndividual(Individual):
|
|
809
849
|
"""Used to represent an Individual on the assembly line project.
|
|
@@ -1562,18 +1602,18 @@ class ALIndividual(Individual):
|
|
|
1562
1602
|
)
|
|
1563
1603
|
|
|
1564
1604
|
def pronoun(self, **kwargs) -> str:
|
|
1565
|
-
"""Returns an objective pronoun as appropriate, based on
|
|
1605
|
+
"""Returns an objective pronoun as appropriate, based on the user's `pronouns` attribute or `gender` attribute.
|
|
1566
1606
|
|
|
1567
|
-
The pronoun could be "you," "her," "him," "it," or "them"
|
|
1568
|
-
|
|
1569
|
-
is the current user.
|
|
1607
|
+
The pronoun could be "I", "you," "her," "him," "it," or "them", or a user-provided pronoun.
|
|
1608
|
+
If the user has selected multiple pronouns, each will appear, separated by a "/".
|
|
1570
1609
|
|
|
1571
|
-
|
|
1572
|
-
|
|
1610
|
+
This method will not trigger the definition of `gender` or `pronouns`, but it will use them if they are defined,
|
|
1611
|
+
with `pronouns` taking precedence. As a default, it will either use the value of `default` or the individual's full name.
|
|
1573
1612
|
|
|
1574
1613
|
Args:
|
|
1575
|
-
**kwargs: Additional keyword arguments.
|
|
1576
|
-
|
|
1614
|
+
**kwargs: Additional keyword arguments that are defined [upstream](https://docassemble.org/docs/objects.html#language%20methods).
|
|
1615
|
+
- person (Optional[[Union[str,int]]): Whether to use a first, second, or third person pronoun. Can be one of 1/"1p", 2/"2p", or 3/"3p" (default is 3). See [upstream](https://docassemble.org/docs/objects.html#language%20methods) documentation for more information.
|
|
1616
|
+
- default (Optional[str]): The default word to use if the pronoun is not defined, e.g. "the agent". If not defined, the default term is the user's name.
|
|
1577
1617
|
Returns:
|
|
1578
1618
|
str: The appropriate pronoun.
|
|
1579
1619
|
"""
|
|
@@ -1583,49 +1623,64 @@ class ALIndividual(Individual):
|
|
|
1583
1623
|
# Use the parent version of pronoun
|
|
1584
1624
|
return super().pronoun(**kwargs)
|
|
1585
1625
|
|
|
1586
|
-
if
|
|
1587
|
-
|
|
1626
|
+
if "default" in kwargs:
|
|
1627
|
+
default = kwargs.pop("default")
|
|
1588
1628
|
else:
|
|
1589
|
-
|
|
1629
|
+
default = self.name_full()
|
|
1630
|
+
|
|
1631
|
+
if hasattr(self, "pronouns") and self.pronouns:
|
|
1632
|
+
if isinstance(self.pronouns, str):
|
|
1633
|
+
pronouns = DADict(elements={self.pronouns.lower(): True})
|
|
1634
|
+
else:
|
|
1635
|
+
pronouns = self.pronouns
|
|
1590
1636
|
|
|
1591
1637
|
if self == this_thread.global_vars.user:
|
|
1592
1638
|
output = word("you", **kwargs)
|
|
1593
|
-
elif (
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1639
|
+
elif hasattr(self, "pronouns") and self.pronouns:
|
|
1640
|
+
pronouns_to_use = []
|
|
1641
|
+
if isinstance(pronouns, DADict):
|
|
1642
|
+
for pronoun in pronouns.true_values():
|
|
1643
|
+
if pronoun in [
|
|
1644
|
+
"she/her/hers",
|
|
1645
|
+
"he/him/his",
|
|
1646
|
+
"they/them/theirs",
|
|
1647
|
+
"ze/zir/zirs",
|
|
1648
|
+
]:
|
|
1649
|
+
if pronoun == "she/her/hers":
|
|
1650
|
+
pronouns_to_use.append(word("her", **kwargs))
|
|
1651
|
+
elif pronoun == "he/him/his":
|
|
1652
|
+
pronouns_to_use.append(word("him", **kwargs))
|
|
1653
|
+
elif pronoun == "they/them/theirs":
|
|
1654
|
+
pronouns_to_use.append(word("them", **kwargs))
|
|
1655
|
+
elif pronoun == "ze/zir/zirs":
|
|
1656
|
+
pronouns_to_use.append(word("zir", **kwargs))
|
|
1657
|
+
elif pronoun == "self-described" and has_parsable_pronouns(
|
|
1658
|
+
self.pronouns_self_described
|
|
1659
|
+
):
|
|
1660
|
+
pronouns_to_use.append(
|
|
1661
|
+
parse_custom_pronouns(self.pronouns_self_described)["o"]
|
|
1662
|
+
)
|
|
1663
|
+
elif has_parsable_pronouns(pronoun):
|
|
1664
|
+
pronouns_to_use.append(parse_custom_pronouns(pronoun)["o"])
|
|
1665
|
+
if len(pronouns_to_use) > 0:
|
|
1666
|
+
output = "/".join(pronouns_to_use)
|
|
1667
|
+
else:
|
|
1668
|
+
output = default
|
|
1618
1669
|
elif hasattr(self, "person_type") and self.person_type in [
|
|
1619
1670
|
"business",
|
|
1620
1671
|
"organization",
|
|
1621
1672
|
]:
|
|
1622
1673
|
output = word("it", **kwargs)
|
|
1623
|
-
elif self
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1674
|
+
elif hasattr(self, "gender"):
|
|
1675
|
+
if self.gender.lower() == "female":
|
|
1676
|
+
output = word("her", **kwargs)
|
|
1677
|
+
elif self.gender.lower() == "male":
|
|
1678
|
+
output = word("him", **kwargs)
|
|
1679
|
+
else:
|
|
1680
|
+
output = word("them", **kwargs)
|
|
1627
1681
|
else:
|
|
1628
|
-
output =
|
|
1682
|
+
output = default
|
|
1683
|
+
|
|
1629
1684
|
if "capitalize" in kwargs and kwargs["capitalize"]:
|
|
1630
1685
|
return capitalize(output)
|
|
1631
1686
|
return output
|
|
@@ -1642,18 +1697,24 @@ class ALIndividual(Individual):
|
|
|
1642
1697
|
return self.pronoun(**kwargs)
|
|
1643
1698
|
|
|
1644
1699
|
def pronoun_possessive(self, target, **kwargs) -> str:
|
|
1645
|
-
"""
|
|
1700
|
+
"""
|
|
1701
|
+
Returns a possessive pronoun and a target word, based on attributes.
|
|
1702
|
+
|
|
1703
|
+
This method will not trigger the definition of `gender` or `pronouns`, but it will use them if they are defined,
|
|
1704
|
+
with `pronouns` taking precedence. As a default, it will either use the value of `default` or the individual's full name.
|
|
1646
1705
|
|
|
1647
1706
|
Given a target word, the function returns "{pronoun} {target}". The pronoun could be
|
|
1648
|
-
"her," "his," "its," or "their". It depends on the `gender` and `person_type` attributes
|
|
1707
|
+
"my", "her," "his," "its," or "their". It depends on the `gender` and `person_type` attributes
|
|
1649
1708
|
and whether the individual is the current user.
|
|
1650
1709
|
|
|
1651
1710
|
Args:
|
|
1652
1711
|
target (str): The target word to follow the pronoun.
|
|
1653
|
-
**kwargs: Additional keyword arguments.
|
|
1712
|
+
**kwargs: Additional keyword arguments that can be passed to modify the behavior. These might include:
|
|
1713
|
+
- `default` (Optional[str]): The default word to use if the pronoun is not defined, e.g., "the agent". If not defined, the default term is the user's name.
|
|
1714
|
+
- `person` (Optional[Union[str, int]]): Whether to use a first, second, or third person pronoun. Can be one of 1/"1p", 2/"2p", or 3/"3p" (default is 3). See [upstream documentation](https://docassemble.org/docs/objects.html#language%20methods) for more information.
|
|
1654
1715
|
|
|
1655
1716
|
Returns:
|
|
1656
|
-
str: The appropriate possessive phrase.
|
|
1717
|
+
str: The appropriate possessive phrase, e.g., "her book", "their document".
|
|
1657
1718
|
"""
|
|
1658
1719
|
person = str(kwargs.get("person", self.get_point_of_view()))
|
|
1659
1720
|
|
|
@@ -1666,50 +1727,64 @@ class ALIndividual(Individual):
|
|
|
1666
1727
|
else:
|
|
1667
1728
|
pronouns = self.pronouns
|
|
1668
1729
|
|
|
1730
|
+
if "default" in kwargs:
|
|
1731
|
+
default = kwargs.pop("default")
|
|
1732
|
+
else:
|
|
1733
|
+
default = self.name_full()
|
|
1734
|
+
|
|
1669
1735
|
if self == this_thread.global_vars.user and (
|
|
1670
1736
|
"thirdperson" not in kwargs or not kwargs["thirdperson"]
|
|
1671
1737
|
):
|
|
1672
1738
|
output = your(target, **kwargs)
|
|
1673
|
-
elif (
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1739
|
+
elif hasattr(self, "pronouns") and self.pronouns:
|
|
1740
|
+
pronouns_to_use = []
|
|
1741
|
+
if isinstance(pronouns, DADict):
|
|
1742
|
+
for pronoun in pronouns.true_values():
|
|
1743
|
+
if pronoun in [
|
|
1744
|
+
"she/her/hers",
|
|
1745
|
+
"he/him/his",
|
|
1746
|
+
"they/them/theirs",
|
|
1747
|
+
"ze/zir/zirs",
|
|
1748
|
+
]:
|
|
1749
|
+
if pronoun == "she/her/hers":
|
|
1750
|
+
pronouns_to_use.append(her(target, **kwargs))
|
|
1751
|
+
elif pronoun == "he/him/his":
|
|
1752
|
+
pronouns_to_use.append(his(target, **kwargs))
|
|
1753
|
+
elif pronoun == "they/them/theirs":
|
|
1754
|
+
pronouns_to_use.append(their(target, **kwargs))
|
|
1755
|
+
elif pronoun == "ze/zir/zirs":
|
|
1756
|
+
pronouns_to_use.append(word("zir", **kwargs) + " " + target)
|
|
1757
|
+
elif pronoun == "self-described" and has_parsable_pronouns(
|
|
1758
|
+
self.pronouns_self_described
|
|
1759
|
+
):
|
|
1760
|
+
pronouns_to_use.append(
|
|
1761
|
+
parse_custom_pronouns(self.pronouns_self_described)["p"]
|
|
1762
|
+
+ " "
|
|
1763
|
+
+ target
|
|
1764
|
+
)
|
|
1765
|
+
elif has_parsable_pronouns(pronoun):
|
|
1766
|
+
pronouns_to_use.append(
|
|
1767
|
+
parse_custom_pronouns(pronoun)["p"] + " " + target
|
|
1768
|
+
)
|
|
1769
|
+
if len(pronouns_to_use) > 0:
|
|
1770
|
+
output = "/".join(pronouns_to_use)
|
|
1771
|
+
else:
|
|
1772
|
+
output = default
|
|
1702
1773
|
elif hasattr(self, "person_type") and self.person_type in [
|
|
1703
1774
|
"business",
|
|
1704
1775
|
"organization",
|
|
1705
1776
|
]:
|
|
1706
1777
|
output = its(target, **kwargs)
|
|
1707
|
-
elif self
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1778
|
+
elif hasattr(self, "gender"):
|
|
1779
|
+
if self.gender.lower() == "female":
|
|
1780
|
+
output = her(target, **kwargs)
|
|
1781
|
+
elif self.gender.lower() == "male":
|
|
1782
|
+
output = his(target, **kwargs)
|
|
1783
|
+
else:
|
|
1784
|
+
output = their(target, **kwargs)
|
|
1711
1785
|
else:
|
|
1712
|
-
output =
|
|
1786
|
+
output = default
|
|
1787
|
+
|
|
1713
1788
|
if "capitalize" in kwargs and kwargs["capitalize"]:
|
|
1714
1789
|
return capitalize(output)
|
|
1715
1790
|
return output
|
|
@@ -1717,13 +1792,14 @@ class ALIndividual(Individual):
|
|
|
1717
1792
|
def pronoun_subjective(self, **kwargs) -> str:
|
|
1718
1793
|
"""Returns a subjective pronoun, based on attributes.
|
|
1719
1794
|
|
|
1720
|
-
The pronoun could be "you," "she," "he," "it," or "they". It depends
|
|
1795
|
+
The pronoun could be "you," "we", "she," "he," "it," or "they". It depends
|
|
1721
1796
|
on the `gender` and `person_type` attributes and whether the individual
|
|
1722
1797
|
is the current user.
|
|
1723
1798
|
|
|
1724
1799
|
Args:
|
|
1725
|
-
**kwargs: Additional keyword arguments.
|
|
1726
|
-
|
|
1800
|
+
**kwargs: Additional keyword arguments that are defined [upstream](https://docassemble.org/docs/objects.html#language%20methods).
|
|
1801
|
+
- person (Optional[[Union[str,int]]): Whether to use a first, second, or third person pronoun. Can be one of 1/"1p", 2/"2p", or 3/"3p" (default is 3). See [upstream](https://docassemble.org/docs/objects.html#language%20methods) documentation for more information.
|
|
1802
|
+
- default (Optional[str]): The default word to use if the pronoun is not defined, e.g. "the agent". If not defined, the default term is the user's name.
|
|
1727
1803
|
Returns:
|
|
1728
1804
|
str: The appropriate subjective pronoun.
|
|
1729
1805
|
"""
|
|
@@ -1732,53 +1808,169 @@ class ALIndividual(Individual):
|
|
|
1732
1808
|
if person in ("1", "1p", "2", "2p"):
|
|
1733
1809
|
# Use the parent version of pronoun
|
|
1734
1810
|
return super().pronoun_subjective(**kwargs)
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
pronouns = DADict(elements={self.pronouns.lower(): True})
|
|
1811
|
+
if "default" in kwargs:
|
|
1812
|
+
default = kwargs.pop("default")
|
|
1738
1813
|
else:
|
|
1739
|
-
|
|
1814
|
+
default = self.name_full()
|
|
1740
1815
|
|
|
1741
|
-
if self
|
|
1742
|
-
|
|
1743
|
-
|
|
1816
|
+
if hasattr(self, "pronouns") and self.pronouns:
|
|
1817
|
+
if isinstance(self.pronouns, str):
|
|
1818
|
+
pronouns = DADict(elements={self.pronouns.lower(): True})
|
|
1819
|
+
else:
|
|
1820
|
+
pronouns = self.pronouns
|
|
1821
|
+
|
|
1822
|
+
if self == this_thread.global_vars.user:
|
|
1744
1823
|
output = word("you", **kwargs)
|
|
1745
|
-
elif (
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1824
|
+
elif hasattr(self, "pronouns") and self.pronouns:
|
|
1825
|
+
pronouns_to_use = []
|
|
1826
|
+
if isinstance(pronouns, DADict):
|
|
1827
|
+
for pronoun in pronouns.true_values():
|
|
1828
|
+
if pronoun in [
|
|
1829
|
+
"she/her/hers",
|
|
1830
|
+
"he/him/his",
|
|
1831
|
+
"they/them/theirs",
|
|
1832
|
+
"ze/zir/zirs",
|
|
1833
|
+
]:
|
|
1834
|
+
if pronoun == "she/her/hers":
|
|
1835
|
+
pronouns_to_use.append(word("she", **kwargs))
|
|
1836
|
+
elif pronoun == "he/him/his":
|
|
1837
|
+
pronouns_to_use.append(word("he", **kwargs))
|
|
1838
|
+
elif pronoun == "they/them/theirs":
|
|
1839
|
+
pronouns_to_use.append(word("they", **kwargs))
|
|
1840
|
+
elif pronoun == "ze/zir/zirs":
|
|
1841
|
+
pronouns_to_use.append(word("ze", **kwargs))
|
|
1842
|
+
elif pronoun == "self-described" and has_parsable_pronouns(
|
|
1843
|
+
self.pronouns_self_described
|
|
1844
|
+
):
|
|
1845
|
+
pronouns_to_use.append(
|
|
1846
|
+
parse_custom_pronouns(self.pronouns_self_described)["s"]
|
|
1847
|
+
)
|
|
1848
|
+
elif has_parsable_pronouns(pronoun):
|
|
1849
|
+
pronouns_to_use.append(parse_custom_pronouns(pronoun)["s"])
|
|
1850
|
+
if len(pronouns_to_use) > 0:
|
|
1851
|
+
output = "/".join(pronouns_to_use)
|
|
1852
|
+
else:
|
|
1853
|
+
output = default
|
|
1854
|
+
elif hasattr(self, "person_type") and self.person_type in [
|
|
1855
|
+
"business",
|
|
1856
|
+
"organization",
|
|
1857
|
+
]:
|
|
1858
|
+
output = word("it", **kwargs)
|
|
1859
|
+
elif hasattr(self, "gender"):
|
|
1860
|
+
if self.gender.lower() == "female":
|
|
1761
1861
|
output = word("she", **kwargs)
|
|
1762
|
-
elif
|
|
1862
|
+
elif self.gender.lower() == "male":
|
|
1763
1863
|
output = word("he", **kwargs)
|
|
1764
|
-
|
|
1864
|
+
else:
|
|
1765
1865
|
output = word("they", **kwargs)
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1866
|
+
else:
|
|
1867
|
+
output = default
|
|
1868
|
+
|
|
1869
|
+
if "capitalize" in kwargs and kwargs["capitalize"]:
|
|
1870
|
+
return capitalize(output)
|
|
1871
|
+
return output
|
|
1872
|
+
|
|
1873
|
+
def pronoun_reflexive(self, **kwargs) -> str:
|
|
1874
|
+
"""Returns the appropriate reflexive pronoun ("herself", "themself", "myself"), based on the user's pronouns or gender and whether we are asked
|
|
1875
|
+
to return a 1st, 2nd, or 3rd person pronoun.
|
|
1876
|
+
|
|
1877
|
+
Note that if the person has pronouns of they/them/theirs or a nonbinary gender, we return "themself" as the singular non-gendered
|
|
1878
|
+
reflexive pronoun and not "themselves". This has growing acceptance although some consider it nonstandard.
|
|
1879
|
+
See: https://www.merriam-webster.com/wordplay/themself
|
|
1880
|
+
|
|
1881
|
+
Args:
|
|
1882
|
+
**kwargs: Additional keyword arguments that are defined [upstream](https://docassemble.org/docs/objects.html#language%20methods).
|
|
1883
|
+
- person (Optional[[Union[str,int]]): Whether to use a first, second, or third person pronoun. Can be one of 1/"1p", 2/"2p", or 3/"3p" (default is 3). See [upstream](https://docassemble.org/docs/objects.html#language%20methods) documentation for more information.
|
|
1884
|
+
- default (Optional[str]): The default word to use if the pronoun is not defined, e.g. "the agent". If not defined, the default term is the user's name.
|
|
1885
|
+
|
|
1886
|
+
Returns:
|
|
1887
|
+
str: The appropriate reflexive pronoun.
|
|
1888
|
+
"""
|
|
1889
|
+
person = str(kwargs.get("person", self.get_point_of_view()))
|
|
1890
|
+
|
|
1891
|
+
if person in ("1", "1p", "2", "2p"):
|
|
1892
|
+
if person == "1":
|
|
1893
|
+
return word("myself")
|
|
1894
|
+
if person == "1p":
|
|
1895
|
+
return word("ourselves")
|
|
1896
|
+
if person == "2":
|
|
1897
|
+
return word("yourself")
|
|
1898
|
+
if person == "2p":
|
|
1899
|
+
return word("yourselves")
|
|
1900
|
+
|
|
1901
|
+
if self == this_thread.global_vars.user:
|
|
1902
|
+
output = word("yourself", **kwargs)
|
|
1903
|
+
|
|
1904
|
+
if "default" in kwargs:
|
|
1905
|
+
default = kwargs.pop("default")
|
|
1906
|
+
else:
|
|
1907
|
+
default = None
|
|
1908
|
+
|
|
1909
|
+
if hasattr(self, "pronouns") and self.pronouns:
|
|
1910
|
+
if isinstance(self.pronouns, str):
|
|
1911
|
+
pronouns = DADict(elements={self.pronouns.lower(): True})
|
|
1912
|
+
else:
|
|
1913
|
+
pronouns = self.pronouns
|
|
1914
|
+
else:
|
|
1915
|
+
pronouns = None
|
|
1916
|
+
|
|
1917
|
+
if self == this_thread.global_vars.user:
|
|
1918
|
+
output = word("yourself", **kwargs)
|
|
1919
|
+
elif hasattr(self, "pronouns") and self.pronouns:
|
|
1920
|
+
pronouns_to_use = []
|
|
1921
|
+
|
|
1922
|
+
if isinstance(pronouns, DADict):
|
|
1923
|
+
for pronoun in pronouns.true_values():
|
|
1924
|
+
if pronoun in [
|
|
1925
|
+
"she/her/hers",
|
|
1926
|
+
"he/him/his",
|
|
1927
|
+
"they/them/theirs",
|
|
1928
|
+
"ze/zir/zirs",
|
|
1929
|
+
]:
|
|
1930
|
+
if pronoun == "she/her/hers":
|
|
1931
|
+
pronouns_to_use.append(word("herself", **kwargs))
|
|
1932
|
+
elif pronoun == "he/him/his":
|
|
1933
|
+
pronouns_to_use.append(word("himself", **kwargs))
|
|
1934
|
+
elif pronoun == "they/them/theirs":
|
|
1935
|
+
pronouns_to_use.append(word("themself", **kwargs))
|
|
1936
|
+
elif pronoun == "ze/zir/zirs":
|
|
1937
|
+
pronouns_to_use.append(word("zirself", **kwargs))
|
|
1938
|
+
elif pronoun == "self-described" and has_parsable_pronouns(
|
|
1939
|
+
self.pronouns_self_described
|
|
1940
|
+
):
|
|
1941
|
+
pronouns_to_use.append(
|
|
1942
|
+
parse_custom_pronouns(self.pronouns_self_described)["o"]
|
|
1943
|
+
+ word("self")
|
|
1944
|
+
)
|
|
1945
|
+
elif has_parsable_pronouns(pronoun):
|
|
1946
|
+
pronouns_to_use.append(
|
|
1947
|
+
parse_custom_pronouns(pronoun)["o"] + word("self")
|
|
1948
|
+
)
|
|
1949
|
+
if len(pronouns_to_use) > 0:
|
|
1950
|
+
output = "/".join(pronouns_to_use)
|
|
1951
|
+
else:
|
|
1952
|
+
output = default
|
|
1770
1953
|
elif hasattr(self, "person_type") and self.person_type in [
|
|
1771
1954
|
"business",
|
|
1772
1955
|
"organization",
|
|
1773
1956
|
]:
|
|
1774
|
-
output = word("
|
|
1775
|
-
elif self
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1957
|
+
output = word("itself", **kwargs)
|
|
1958
|
+
elif hasattr(self, "gender"):
|
|
1959
|
+
if self.gender.lower() == "female":
|
|
1960
|
+
output = word("herself", **kwargs)
|
|
1961
|
+
elif self.gender.lower() == "male":
|
|
1962
|
+
output = word("himself", **kwargs)
|
|
1963
|
+
else:
|
|
1964
|
+
output = word("themself", **kwargs)
|
|
1779
1965
|
else:
|
|
1780
|
-
|
|
1781
|
-
|
|
1966
|
+
if default:
|
|
1967
|
+
output = default
|
|
1968
|
+
else:
|
|
1969
|
+
output = word(
|
|
1970
|
+
"themself"
|
|
1971
|
+
) # reflexive pronoun shouldn't be the person's name
|
|
1972
|
+
|
|
1973
|
+
if kwargs.get("capitalize"):
|
|
1782
1974
|
return capitalize(output)
|
|
1783
1975
|
return output
|
|
1784
1976
|
|
|
@@ -425,4 +425,19 @@ code: |
|
|
|
425
425
|
code: |
|
|
426
426
|
LOGO_TITLE_ROW_2 = config_with_language_fallback("logo title row 2")
|
|
427
427
|
---
|
|
428
|
-
code:
|
|
428
|
+
code: |
|
|
429
|
+
al_sessions_to_exclude_from_interview_list = (
|
|
430
|
+
get_config("assembly line", {})
|
|
431
|
+
.get("interview list", {})
|
|
432
|
+
.get(
|
|
433
|
+
"exclude from interview list",
|
|
434
|
+
get_config("assembly line", {}).get(
|
|
435
|
+
"exclude from interview list",
|
|
436
|
+
[
|
|
437
|
+
"docassemble.ALDashboard",
|
|
438
|
+
"docassemble.AssemblyLine:data/questions/al_saved_sessions_store.yml",
|
|
439
|
+
"docassemble.AssemblyLine:data/questions/interview_list.yml",
|
|
440
|
+
],
|
|
441
|
+
),
|
|
442
|
+
)
|
|
443
|
+
)
|
|
@@ -334,54 +334,12 @@ def get_saved_interview_list(
|
|
|
334
334
|
offset (int, optional): The offset to start returning results from. Defaults to 0.
|
|
335
335
|
filename_to_exclude (str, optional): The filename to exclude from the results. Defaults to "".
|
|
336
336
|
exclude_current_filename (bool, optional): Whether to exclude the current filename from the results. Defaults to True.
|
|
337
|
-
exclude_filenames (Optional[List[str]], optional):
|
|
337
|
+
exclude_filenames (Optional[List[str]], optional): List of filenames to exclude. Defaults to None. If the `filename` does not contain a `:` it will be treated as a prefix, allowing you to filter out whole packages (e.g., any path starting with docassemble.ALDashboard or docassemble.playground)
|
|
338
338
|
exclude_newly_started_sessions (bool, optional): Whether to exclude sessions that are still on "step 1". Defaults to False.
|
|
339
339
|
|
|
340
340
|
Returns:
|
|
341
341
|
List[Dict[str, Any]]: A list of saved sessions for the specified filename.
|
|
342
342
|
"""
|
|
343
|
-
# We use an `offset` instead of a cursor because it is simpler and clearer
|
|
344
|
-
# while it appears to be performant enough for real-world usage.
|
|
345
|
-
# Up to ~ 1,000 sessions performs well and is higher than expected for an end-user
|
|
346
|
-
get_sessions_query = text(
|
|
347
|
-
"""
|
|
348
|
-
SELECT userdict.indexno
|
|
349
|
-
,userdict.filename as filename
|
|
350
|
-
,num_keys
|
|
351
|
-
,userdictkeys.user_id as user_id
|
|
352
|
-
,userdict.modtime as modtime
|
|
353
|
-
,userdict.key as key
|
|
354
|
-
,jsonstorage.data->'auto_title' as auto_title
|
|
355
|
-
,jsonstorage.data->'title' as title
|
|
356
|
-
,jsonstorage.data->'description' as description
|
|
357
|
-
,jsonstorage.data->'steps' as steps
|
|
358
|
-
,jsonstorage.data->'progress' as progress
|
|
359
|
-
,jsonstorage.data->'original_interview_filename' as original_interview_filename
|
|
360
|
-
,jsonstorage.data->'answer_count' as answer_count
|
|
361
|
-
,jsonstorage.data as data
|
|
362
|
-
FROM userdict
|
|
363
|
-
NATURAL JOIN
|
|
364
|
-
(
|
|
365
|
-
SELECT key
|
|
366
|
-
,MAX(modtime) AS modtime
|
|
367
|
-
,COUNT(key) AS num_keys
|
|
368
|
-
FROM userdict
|
|
369
|
-
GROUP BY key
|
|
370
|
-
) mostrecent
|
|
371
|
-
LEFT JOIN userdictkeys
|
|
372
|
-
ON userdictkeys.key = userdict.key
|
|
373
|
-
LEFT JOIN jsonstorage
|
|
374
|
-
ON userdict.key = jsonstorage.key AND (jsonstorage.tags = :metadata)
|
|
375
|
-
WHERE (userdictkeys.user_id = :user_id or :user_id is null)
|
|
376
|
-
AND (userdict.filename = :filename OR :filename is null)
|
|
377
|
-
AND (userdict.filename NOT IN :filenames_to_exclude)
|
|
378
|
-
AND (NOT :exclude_newly_started_sessions OR num_keys > 1)
|
|
379
|
-
ORDER BY modtime desc
|
|
380
|
-
LIMIT :limit
|
|
381
|
-
OFFSET :offset;
|
|
382
|
-
"""
|
|
383
|
-
)
|
|
384
|
-
|
|
385
343
|
if offset < 0:
|
|
386
344
|
offset = 0
|
|
387
345
|
|
|
@@ -393,10 +351,69 @@ def get_saved_interview_list(
|
|
|
393
351
|
current_filename = ""
|
|
394
352
|
if not filename_to_exclude:
|
|
395
353
|
filename_to_exclude = ""
|
|
396
|
-
filenames_to_exclude = []
|
|
354
|
+
filenames_to_exclude: List[str] = []
|
|
355
|
+
packages_to_exclude: List[str] = []
|
|
397
356
|
if exclude_filenames:
|
|
398
|
-
filenames_to_exclude
|
|
357
|
+
for f in filenames_to_exclude:
|
|
358
|
+
if f and (":" not in f):
|
|
359
|
+
packages_to_exclude.append(f)
|
|
360
|
+
else:
|
|
361
|
+
filenames_to_exclude.append(f)
|
|
399
362
|
filenames_to_exclude.extend([current_filename, filename_to_exclude])
|
|
363
|
+
|
|
364
|
+
query_draft = """
|
|
365
|
+
SELECT userdict.indexno
|
|
366
|
+
,userdict.filename as filename
|
|
367
|
+
,num_keys
|
|
368
|
+
,userdictkeys.user_id as user_id
|
|
369
|
+
,userdict.modtime as modtime
|
|
370
|
+
,userdict.key as key
|
|
371
|
+
,jsonstorage.data->'auto_title' as auto_title
|
|
372
|
+
,jsonstorage.data->'title' as title
|
|
373
|
+
,jsonstorage.data->'description' as description
|
|
374
|
+
,jsonstorage.data->'steps' as steps
|
|
375
|
+
,jsonstorage.data->'progress' as progress
|
|
376
|
+
,jsonstorage.data->'original_interview_filename' as original_interview_filename
|
|
377
|
+
,jsonstorage.data->'answer_count' as answer_count
|
|
378
|
+
,jsonstorage.data as data
|
|
379
|
+
FROM userdict
|
|
380
|
+
NATURAL JOIN
|
|
381
|
+
(
|
|
382
|
+
SELECT key
|
|
383
|
+
,MAX(modtime) AS modtime
|
|
384
|
+
,COUNT(key) AS num_keys
|
|
385
|
+
FROM userdict
|
|
386
|
+
GROUP BY key
|
|
387
|
+
) mostrecent
|
|
388
|
+
LEFT JOIN userdictkeys
|
|
389
|
+
ON userdictkeys.key = userdict.key
|
|
390
|
+
LEFT JOIN jsonstorage
|
|
391
|
+
ON userdict.key = jsonstorage.key AND (jsonstorage.tags = :metadata)
|
|
392
|
+
WHERE (userdictkeys.user_id = :user_id or :user_id is null)
|
|
393
|
+
AND (userdict.filename = :filename OR :filename is null)
|
|
394
|
+
AND (userdict.filename NOT IN :filenames_to_exclude)
|
|
395
|
+
AND (NOT :exclude_newly_started_sessions OR num_keys > 1)
|
|
396
|
+
"""
|
|
397
|
+
if packages_to_exclude:
|
|
398
|
+
query_draft += (
|
|
399
|
+
"""
|
|
400
|
+
AND (:packages_to_exclude IS NULL OR NOT (
|
|
401
|
+
"""
|
|
402
|
+
+ " OR ".join(
|
|
403
|
+
[f"userdict.filename LIKE '{name}%'" for name in packages_to_exclude]
|
|
404
|
+
)
|
|
405
|
+
+ """
|
|
406
|
+
))
|
|
407
|
+
"""
|
|
408
|
+
)
|
|
409
|
+
query_draft += """
|
|
410
|
+
ORDER BY modtime desc
|
|
411
|
+
LIMIT :limit
|
|
412
|
+
OFFSET :offset;
|
|
413
|
+
"""
|
|
414
|
+
|
|
415
|
+
get_sessions_query = text(query_draft)
|
|
416
|
+
|
|
400
417
|
if user_id is None:
|
|
401
418
|
if user_logged_in():
|
|
402
419
|
user_id = user_info().id
|
|
@@ -427,6 +444,9 @@ def get_saved_interview_list(
|
|
|
427
444
|
"offset": offset,
|
|
428
445
|
"filenames_to_exclude": tuple(filenames_to_exclude),
|
|
429
446
|
"exclude_newly_started_sessions": exclude_newly_started_sessions,
|
|
447
|
+
"packages_to_exclude": (
|
|
448
|
+
None if not packages_to_exclude else "present"
|
|
449
|
+
), # We need to pass a value to the query, but it's treated as a flag
|
|
430
450
|
},
|
|
431
451
|
)
|
|
432
452
|
sessions = []
|
|
@@ -486,10 +506,13 @@ def find_matching_sessions(
|
|
|
486
506
|
)
|
|
487
507
|
|
|
488
508
|
# Construct the dynamic part of the SQL query for metadata column selection and keyword search
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
509
|
+
if keyword:
|
|
510
|
+
metadata_search_conditions = " OR ".join(
|
|
511
|
+
f"COALESCE(jsonstorage.data->>{repr(column)}, '') ILIKE '%' || :keyword || '%'"
|
|
512
|
+
for column in metadata_column_names
|
|
513
|
+
)
|
|
514
|
+
else:
|
|
515
|
+
metadata_search_conditions = "TRUE"
|
|
493
516
|
|
|
494
517
|
# we retrieve the default metadata columns even if we don't search them
|
|
495
518
|
metadata_column_names = set(metadata_column_names).union(
|
|
@@ -565,19 +588,23 @@ def find_matching_sessions(
|
|
|
565
588
|
log("Asked to get interview list for user that is not logged in")
|
|
566
589
|
return []
|
|
567
590
|
|
|
591
|
+
parameters = {
|
|
592
|
+
"metadata": metadata_key_name,
|
|
593
|
+
"keyword": keyword,
|
|
594
|
+
"user_id": user_id,
|
|
595
|
+
"limit": limit,
|
|
596
|
+
"offset": offset,
|
|
597
|
+
"filenames_to_exclude": tuple(filenames_to_exclude),
|
|
598
|
+
"exclude_newly_started_sessions": exclude_newly_started_sessions,
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
# Add filename parameters
|
|
602
|
+
if filenames:
|
|
603
|
+
for i, filename in enumerate(filenames):
|
|
604
|
+
parameters[f"filename{i}"] = filename
|
|
605
|
+
|
|
568
606
|
with db.connect() as con:
|
|
569
|
-
rs = con.execute(
|
|
570
|
-
get_sessions_query,
|
|
571
|
-
{
|
|
572
|
-
"metadata": metadata_key_name,
|
|
573
|
-
"keyword": keyword,
|
|
574
|
-
"user_id": user_id,
|
|
575
|
-
"limit": limit,
|
|
576
|
-
"offset": offset,
|
|
577
|
-
"filenames_to_exclude": tuple(filenames_to_exclude),
|
|
578
|
-
"exclude_newly_started_sessions": exclude_newly_started_sessions,
|
|
579
|
-
},
|
|
580
|
-
)
|
|
607
|
+
rs = con.execute(get_sessions_query, parameters)
|
|
581
608
|
|
|
582
609
|
sessions = []
|
|
583
610
|
for session in rs:
|
|
@@ -921,7 +948,7 @@ def session_list_html(
|
|
|
921
948
|
metadata_key_name (str, optional): Name of the metadata key. Defaults to "metadata".
|
|
922
949
|
filename_to_exclude (str, optional): Name of the file to exclude. Defaults to `al_session_store_default_filename`.
|
|
923
950
|
exclude_current_filename (bool, optional): If True, excludes the current filename. Defaults to True.
|
|
924
|
-
exclude_filenames (Optional[List[str]], optional): List of filenames to exclude. Defaults to None.
|
|
951
|
+
exclude_filenames (Optional[List[str]], optional): List of filenames to exclude. Defaults to None. If the `filename` does not contain a `:` it will be treated as a prefix, allowing you to filter out whole packages (e.g., any path starting with docassemble.ALDashboard or docassemble.playground)
|
|
925
952
|
exclude_newly_started_sessions (bool, optional): If True, excludes newly started sessions. Defaults to False.
|
|
926
953
|
name_label (str, optional): Label for the session name/title. Defaults to translated word "Title".
|
|
927
954
|
date_label (str, optional): Label for the date column. Defaults to translated word "Date modified".
|
|
@@ -938,6 +965,7 @@ def session_list_html(
|
|
|
938
965
|
limit (int, optional): Limit for the number of sessions returned. Defaults to 50.
|
|
939
966
|
offset (int, optional): Offset for the session list. Defaults to 0.
|
|
940
967
|
|
|
968
|
+
|
|
941
969
|
Returns:
|
|
942
970
|
str: HTML-formatted table containing the list of user sessions.
|
|
943
971
|
"""
|
|
@@ -61,6 +61,8 @@ class TestALIndividual(unittest.TestCase):
|
|
|
61
61
|
# Assigning this_thread to self.individual
|
|
62
62
|
self.individual.this_thread = self.this_thread
|
|
63
63
|
|
|
64
|
+
self.individual.name.first = "John"
|
|
65
|
+
|
|
64
66
|
def test_phone_numbers(self):
|
|
65
67
|
self.assertEqual(self.individual.phone_numbers(), "")
|
|
66
68
|
self.individual.phone_number = ""
|
|
@@ -423,9 +425,7 @@ class TestALIndividual(unittest.TestCase):
|
|
|
423
425
|
self.assertEqual(self.individual.pronoun_possessive("fish"), "xem fish")
|
|
424
426
|
|
|
425
427
|
self.individual.pronouns_self_described = "Xe/Xir/Xirs/xem/xirself"
|
|
426
|
-
|
|
427
|
-
with self.assertRaises(DAAttributeError):
|
|
428
|
-
self.individual.pronoun_objective()
|
|
428
|
+
self.assertEqual(self.individual.pronoun_objective(), "John")
|
|
429
429
|
|
|
430
430
|
def test_name_methods(self):
|
|
431
431
|
self.individual.name.first = "John"
|
|
@@ -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='3.0
|
|
47
|
+
version='3.1.0',
|
|
48
48
|
description=(''),
|
|
49
49
|
long_description='# Suffolk LIT Lab Document Assembly Line\r\n\r\n[](https://badge.fury.io/py/docassemble-AssemblyLine)\r\n\r\n<img src="https://user-images.githubusercontent.com/7645641/142245862-c2eb02ab-3090-4e97-9653-bb700bf4c54d.png" alt="drawing" width="300" alt="work together" style="align: center;"/>\r\n\r\nThe Assembly Line Project is a collection of volunteers, students, and institutions who joined together\r\nduring the COVID-19 pandemic to help increase access to the court system. Our vision is mobile-friendly,\r\neasy to use **guided** online forms that help empower litigants to access the court remotely.\r\n\r\nOur signature project is [CourtFormsOnline.org](https://courtformsonline.org).\r\n\r\nWe designed a step-by-step, assembly line style process for automating court forms on top of Docassemble\r\nand built several tools along the way that **you** can use in your home jurisdiction.\r\n\r\nThis package contains **runtime code** and **pre-written questions** to support authoring robust, \r\nconsistent, and attractive Docassemble interviews that help complete court forms.\r\n\r\nRead more on our [documentation page](https://suffolklitlab.org/docassemble-AssemblyLine-documentation/).\r\n\r\n\r\n# Related repositories\r\n\r\n* https://github.com/SuffolkLitLab/docassemble-ALWeaver\r\n* https://github.com/SuffolkLitLab/docassemble-ALMassachusetts\r\n* https://github.com/SuffolkLitLab/docassemble-MassAccess\r\n* https://github.com/SuffolkLitLab/docassemble-ALThemeTemplate\r\n* https://github.com/SuffolkLitLab/EfileProxyServer\r\n\r\n# Documentation\r\n\r\nhttps://suffolklitlab.org/docassemble-AssemblyLine-documentation/\r\n\r\n# Installation\r\n\r\n## Menu-driven installation\r\n\r\nThe recommended installation method is with the [guided installation script](https://suffolklitlab.org/docassemble-AssemblyLine-documentation/docs/installation).\r\n\r\n## Manual installation\r\n\r\nNormally you do not need to manually install the Assembly Line. Use the [installation script](https://suffolklitlab.org/docassemble-AssemblyLine-documentation/docs/installation)\r\nif you can. The instructions below are for your optional reference.\r\n\r\nThis package depends on the following configuration changes on your Docassemble server:\r\n\r\n* Ensure that [font-awesome](https://docassemble.org/docs/config.html#default%20icons) is enabled (this may be on by default:\r\n```yaml\r\ndefault icons: font awesome\r\n```\r\n* Add a [Google API key](https://docassemble.org/docs/config.html#google) that has access to:\r\n * Google Places API\r\n * Google Geocoding API\r\n* Add a [VoiceRSS API key](https://docassemble.org/docs/config.html#voicerss)\r\n* Add a [Twilio API key](https://docassemble.org/docs/config.html#twilio) for SMS support\r\n* Add an email account: [Mailgun](https://docassemble.org/docs/config.html#mailgun%20api) or [SendGrid](https://docassemble.org/docs/config.html#sendgrid%20api) recommended for email support\r\n* To show package update time and to enable the feedback form, add a GitHub Private Access token to your config.yml file, like this:\r\n```yaml\r\n# Needs access to create new issues on repositories\r\ngithub issues:\r\n username: "suffolklitlab-issues"\r\n token: "12345"\r\n# Does not need any special access to public repositories \r\ngithub readonly:\r\n username: "suffolklitlab-issues"\r\n password: "45678"\r\n type: "basic"\r\n```\r\n* If you are also using the [Assembly Line Weaver](https://github.com/SuffolkLITLab/docassemble-assemblylinewizard), you may want to set up a [Docassemble API key](https://docassemble.org/docs/api.html#manage_api) in your config.yml file to allow you to install packages automatically, like this:\r\n```yaml\r\ninstall packages api key: 12345\r\n```\r\n\r\n# Migration\r\n\r\nSee [discussion here](https://github.com/SuffolkLITLab/docassemble-AssemblyLine/issues/69)\r\n\r\n\r\n# ALDocument class\r\n\r\n## Purpose\r\n\r\nThe ALDocument class is a small utility library that makes it simpler to use the following features in an interview:\r\n\r\n* Conditional assembly of multiple, optional documents that are triggered in different ways in your interview\r\n* An addendum for PDF files that makes it simple to deal with overflow text\r\n* A customizable download screen that lists the documents in a neat table\r\n* A customizable "send" button that allows the user to email the final forms to a location of their choice\r\n\r\nHere is a small snippet that you can copy and modify that shows how to use the most important features of the ALDocument class.\r\n\r\n```\r\n---\r\nobjects:\r\n - CRA_Motion_to_Dismiss_attachment: ALDocument.using(filename="CRA_Motion_to_Dismiss", title="Motion to Dismiss CRA", enabled=True, has_addendum=True, default_overflow_message="[See addendum]") \r\n---\r\nobjects:\r\n - al_user_bundle: ALDocumentBundle.using(elements=[CRA_Motion_to_Dismiss_attachment], title="Forms to download and deliver to court", filename="motion_to_dismiss_CRA.pdf")\r\n - al_court_bundle: ALDocumentBundle.using(elements=[CRA_Motion_to_Dismiss_attachment], title="Forms to download and deliver to court", filename="motion_to_dismiss_CRA.pdf")\r\n---\r\ngeneric object: ALDocument\r\nattachment:\r\n variable name: x.addendum\r\n docx template file: docx_addendum.docx\r\n---\r\ncode: |\r\n CRA_Motion_to_Dismiss_attachment.overflow_fields[\'reasons_for_request\'].overflow_trigger = 640\r\n CRA_Motion_to_Dismiss_attachment.overflow_fields[\'reasons_for_request\'].label = "Reasons for request"\r\n CRA_Motion_to_Dismiss_attachment.overflow_fields.gathered = True\r\n \r\n---\r\nattachment:\r\n variable name: CRA_Motion_to_Dismiss_attachment[i]\r\n name: CRA Motion to Dismiss\r\n filename: CRA_Motion_to_Dismiss\r\n skip undefined: True\r\n pdf template file: CRA_Motion_to_Dismiss.pdf\r\n fields: \r\n - "court_county": ${ trial_court.address.county }\r\n - "docket_number": ${ docket_number }\r\n - "user_signature": ${ users[0].signature_if_final(i) }\r\n - "signature_date": ${ signature_date }\r\n```\r\n\r\nIt is very common to have a *contingent* document in ALDocument. If your document is contingent, remove the `enabled=True` from the object declaration, and use\r\nsome other method to "turn on" the attachment.\r\n\r\nE.g.,\r\n\r\n```\r\ncode: |\r\n CRA_Motion_to_Dismiss_attachment.enabled = condition1 and condition2\r\n```\r\n\r\n# Changelog\r\n\r\nSee [CHANGELOG.MD](https://github.com/SuffolkLITLab/docassemble-AssemblyLine/blob/main/CHANGELOG.md)\r\n',
|
|
50
50
|
long_description_content_type='text/markdown',
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = '3.0.1'
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{docassemble_assemblyline-3.0.1 → docassemble_assemblyline-3.1.0}/docassemble/AssemblyLine/py.typed
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|