Skip to content

Commit

Permalink
noun_is_singular keyword parameter to noun_plural; describe method of…
Browse files Browse the repository at this point in the history
… DateTimeDelta expanded to describe times as well as dates; fallback to using repr when reporting errors that require formatting YAML that may be invalid; bug with ip address ban enabled; interview logic history was not displaying unless development site is protected is true
jhpyle committed Mar 15, 2024
1 parent b0847b4 commit 7616c00
Showing 7 changed files with 73 additions and 15 deletions.
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
# Change Log

## [1.4.101] - 2024-03-15

### Added
- The `noun_is_singular` keyword parameter to the `noun_plural()`
function.

### Changed
- The `date_difference()` function's `describe()` method will now
describe times.
- In error messages from YAML parsing, fall back to displaying YAML
with `repr()` if displaying the YAML as YAML fails.

### Fixed
- Bug with `ip address ban enabled`.
- Bug with displaying interview logic history.

## [1.4.100] - 2024-03-07

### Fixed
3 changes: 3 additions & 0 deletions docassemble_base/docassemble/base/data/sources/base-words.yml
Original file line number Diff line number Diff line change
@@ -410,6 +410,7 @@
"Home Page": Null
"Honduras": Null
"Hong Kong": Null
"hour": Null
"How question came to be asked": Null
"How this question came to be asked": Null
"How would you like the data to be imported?": Null
@@ -570,6 +571,7 @@
"Methods": Null
"Mexico": Null
"Micronesia, Federated States of": Null
"minute": Null
"Models": Null
"Modules available in Playground": Null
"Modules defined": Null
@@ -864,6 +866,7 @@
"Score": Null
"Search": Null
"Second factor authentication": Null
"second": Null
"Second subdivision": Null
"Second Subdivision": Null
"Section": Null
30 changes: 24 additions & 6 deletions docassemble_base/docassemble/base/functions.py
Original file line number Diff line number Diff line change
@@ -3150,7 +3150,10 @@ def number_or_length(target):

def noun_plural_en(*pargs, **kwargs):
ensure_definition(*pargs, **kwargs)
noun = noun_singular_en(pargs[0])
if kwargs.get('noun_is_singular', False):
noun = pargs[0]
else:
noun = noun_singular_en(pargs[0])
if len(pargs) >= 2 and number_or_length(pargs[1]) == 1:
return str(noun)
output = docassemble_pattern.en.pluralize(str(noun))
@@ -3209,7 +3212,10 @@ def verb_past_es(*pargs, **kwargs):

def noun_plural_es(*pargs, **kwargs):
ensure_definition(*pargs, **kwargs)
noun = noun_singular_es(pargs[0])
if kwargs.get('noun_is_singular', False):
noun = pargs[0]
else:
noun = noun_singular_es(pargs[0])
if len(pargs) >= 2 and number_or_length(pargs[1]) == 1:
return str(noun)
output = docassemble_pattern.es.pluralize(str(noun))
@@ -3268,7 +3274,10 @@ def verb_past_de(*pargs, **kwargs):

def noun_plural_de(*pargs, **kwargs):
ensure_definition(*pargs, **kwargs)
noun = noun_singular_de(pargs[0])
if kwargs.get('noun_is_singular', False):
noun = pargs[0]
else:
noun = noun_singular_de(pargs[0])
if len(pargs) >= 2 and number_or_length(pargs[1]) == 1:
return str(noun)
output = docassemble_pattern.de.pluralize(str(noun))
@@ -3327,7 +3336,10 @@ def verb_past_fr(*pargs, **kwargs):

def noun_plural_fr(*pargs, **kwargs):
ensure_definition(*pargs, **kwargs)
noun = noun_singular_fr(pargs[0])
if kwargs.get('noun_is_singular', False):
noun = pargs[0]
else:
noun = noun_singular_fr(pargs[0])
if len(pargs) >= 2 and number_or_length(pargs[1]) == 1:
return str(noun)
output = docassemble_pattern.fr.pluralize(str(noun))
@@ -3386,7 +3398,10 @@ def verb_past_it(*pargs, **kwargs):

def noun_plural_it(*pargs, **kwargs):
ensure_definition(*pargs, **kwargs)
noun = noun_singular_it(pargs[0])
if kwargs.get('noun_is_singular', False):
noun = pargs[0]
else:
noun = noun_singular_it(pargs[0])
if len(pargs) >= 2 and number_or_length(pargs[1]) == 1:
return str(noun)
output = docassemble_pattern.it.pluralize(str(noun))
@@ -3445,7 +3460,10 @@ def verb_past_nl(*pargs, **kwargs):

def noun_plural_nl(*pargs, **kwargs):
ensure_definition(*pargs, **kwargs)
noun = noun_singular_nl(pargs[0])
if kwargs.get('noun_is_singular', False):
noun = pargs[0]
else:
noun = noun_singular_nl(pargs[0])
if len(pargs) >= 2 and number_or_length(pargs[1]) == 1:
return str(noun)
output = docassemble_pattern.nl.pluralize(str(noun))
17 changes: 12 additions & 5 deletions docassemble_base/docassemble/base/parse.py
Original file line number Diff line number Diff line change
@@ -2047,11 +2047,18 @@ def process_js_vars(expr):
class Question:

def idebug(self, data):
if hasattr(self, 'from_source') and hasattr(self, 'package'):
if isinstance(self.line_number, int):
return f"\nIn file {self.from_source.path} in the block on line {self.line_number} from package {self.package}:\n\n" + safeyaml.dump_to_string(data)
return "\nIn file " + str(self.from_source.path) + " from package " + str(self.package) + ":\n\n" + safeyaml.dump_to_string(data)
return safeyaml.dump_to_string(data)
try:
if hasattr(self, 'from_source') and hasattr(self, 'package'):
if isinstance(self.line_number, int):
return f"\nIn file {self.from_source.path} in the block on line {self.line_number} from package {self.package}:\n\n" + safeyaml.dump_to_string(data)
return "\nIn file " + str(self.from_source.path) + " from package " + str(self.package) + ":\n\n" + safeyaml.dump_to_string(data)
return safeyaml.dump_to_string(data)
except:
if hasattr(self, 'from_source') and hasattr(self, 'package'):
if isinstance(self.line_number, int):
return f"\nIn file {self.from_source.path} in the block on line {self.line_number} from package {self.package}:\n\n" + repr(data)
return "\nIn file " + str(self.from_source.path) + " from package " + str(self.package) + ":\n\n" + repr(data)
return repr(data)

def id_debug(self, data):
"""One liner info about a YAML block. Used in `compile` for later error reporting."""
19 changes: 16 additions & 3 deletions docassemble_base/docassemble/base/util.py
Original file line number Diff line number Diff line change
@@ -6784,11 +6784,24 @@ def describe(self, **kwargs):
output = []
diff = dateutil.relativedelta.relativedelta(self.end, self.start)
if diff.years != 0:
output.append((abs(diff.years), noun_plural(word('year'), abs(diff.years))))
output.append((abs(diff.years), noun_plural(word('year'), abs(diff.years), noun_is_singular=True)))
if diff.months != 0 and specificity != 'year':
output.append((abs(diff.months), noun_plural(word('month'), abs(diff.months))))
output.append((abs(diff.months), noun_plural(word('month'), abs(diff.months), noun_is_singular=True)))
if diff.days != 0 and specificity not in ('year', 'month'):
output.append((abs(diff.days), noun_plural(word('day'), abs(diff.days))))
output.append((abs(diff.days), noun_plural(word('day'), abs(diff.days), noun_is_singular=True)))
if len(output) == 0 or specificity in ('hour', 'minute', 'second'):
if diff.hours != 0 and specificity not in ('year', 'month', 'day'):
output.append((abs(diff.hours), noun_plural(word('hour'), abs(diff.hours), noun_is_singular=True)))
if (abs(diff.hours) < 2 or specificity in ('minute', 'second')) and diff.minutes != 0 and specificity not in ('year', 'month', 'day', 'hour'):
output.append((abs(diff.minutes), noun_plural(word('minute'), abs(diff.minutes), noun_is_singular=True)))
if len(output) == 0 or specificity == 'second':
if diff.seconds != 0 and specificity not in ('year', 'month', 'day', 'hour', 'minute'):
output.append((abs(diff.seconds), noun_plural(word('second'), abs(diff.seconds), noun_is_singular=True)))
if len(output) == 0:
if specificity is None:
output.append((0, noun_plural(word('second'), 0, noun_is_singular=True)))
else:
output.append((0, noun_plural(word(specificity), 0, noun_is_singular=True)))
if kwargs.get('nice', True):
return_value = comma_and_list(["%s %s" % (nice_number(y[0]), y[1]) for y in output])
if kwargs.get('capitalize', False):
2 changes: 1 addition & 1 deletion docassemble_webapp/docassemble/webapp/server.py
Original file line number Diff line number Diff line change
@@ -23324,7 +23324,7 @@ def server_error(the_error):
if 'in error' not in session and docassemble.base.functions.this_thread.interview is not None and 'error action' in docassemble.base.functions.this_thread.interview.consolidated_metadata:
session['in error'] = True
return index(action_argument={'action': docassemble.base.functions.this_thread.interview.consolidated_metadata['error action'], 'arguments': {'error_message': orig_errmess, 'error_history': the_history, 'error_trace': the_trace}}, refer=['error'])
show_debug = not bool((not (DEBUG and daconfig.get('development site is protected', False))) and isinstance(the_error, (DAError, DAInvalidFilename)))
show_debug = not bool((not ((DEBUG and daconfig.get('development site is protected', False)) or (current_user.is_authenticated and current_user.has_role('admin', 'developer')))) and isinstance(the_error, (DAError, DAInvalidFilename)))
if int(int(error_code)/100) == 4:
show_debug = False
if error_code == 404:
1 change: 1 addition & 0 deletions docassemble_webapp/docassemble/webapp/users/forms.py
Original file line number Diff line number Diff line change
@@ -82,6 +82,7 @@ def ldap_bind(self, connect):
return username, password

def validate(self):
failed_attempts = None
if BAN_IP_ADDRESSES:
key = 'da:failedlogin:ip:' + str(get_requester_ip(request))
failed_attempts = r.get(key)

0 comments on commit 7616c00

Please sign in to comment.