1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2024-09-14 20:13:21 +02:00

Time filter improvements (#359)

* Adjust target directory so that ansible-test knows what to run when filters change.

* Divide by multiple instead of multiplying with product of 1/factor to improve numerical robustness.

* Allow to say what a year or month is (in days).

* Add changelog fragment announcing the time filters.

* Make sure unknown keyword args result in errors.

* Fix formatting screw-up.
This commit is contained in:
Felix Fontein 2020-05-19 11:18:49 +02:00 committed by GitHub
parent 801b1edcbe
commit 0399127d11
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 49 additions and 27 deletions

View file

@ -0,0 +1,2 @@
minor_changes:
- A new filter ``to_time_unit`` with specializations ``to_milliseconds``, ``to_seconds``, ``to_minutes``, ``to_hours``, ``to_days``, ``to_weeks``, ``to_months`` and ``to_years`` has been added. For example ``'2d 4h' | community.general.to_hours`` evaluates to 52.

View file

@ -56,20 +56,23 @@ def multiply(factors):
return result return result
def divide(divisors): def to_time_unit(human_time, unit='ms', **kwargs):
result = 1
for divisor in divisors:
result = result / divisor
return result
def to_time_unit(human_time, unit='ms'):
''' Return a time unit from a human readable string ''' ''' Return a time unit from a human readable string '''
unit = UNIT_TO_SHORT_FORM.get(unit, unit) unit = UNIT_TO_SHORT_FORM.get(unit, unit)
if unit not in UNIT_FACTORS: if unit not in UNIT_FACTORS:
available_units = sorted(list(UNIT_FACTORS.keys()) + list(UNIT_TO_SHORT_FORM.keys())) available_units = sorted(list(UNIT_FACTORS.keys()) + list(UNIT_TO_SHORT_FORM.keys()))
raise AnsibleFilterError("to_time_unit() can not convert to the following unit: %s. " raise AnsibleFilterError("to_time_unit() can not convert to the following unit: %s. "
"Available units: %s" % (unit, ', '.join(available_units))) "Available units: %s" % (unit, ', '.join(available_units)))
unit_factors = UNIT_FACTORS
if 'year' in kwargs:
unit_factors['y'] = unit_factors['y'][:-1] + [kwargs.pop('year')]
if 'month' in kwargs:
unit_factors['mo'] = unit_factors['mo'][:-1] + [kwargs.pop('month')]
if kwargs:
raise AnsibleFilterError('to_time_unit() got unknown keyword arguments: %s' % ', '.join(kwargs.keys()))
result = 0 result = 0
for h_time_string in human_time.split(): for h_time_string in human_time.split():
res = re.match(r'(-?\d+)(\w+)', h_time_string) res = re.match(r'(-?\d+)(\w+)', h_time_string)
@ -81,53 +84,53 @@ def to_time_unit(human_time, unit='ms'):
h_time_unit = res.group(2) h_time_unit = res.group(2)
h_time_unit = UNIT_TO_SHORT_FORM.get(h_time_unit, h_time_unit) h_time_unit = UNIT_TO_SHORT_FORM.get(h_time_unit, h_time_unit)
if h_time_unit not in UNIT_FACTORS: if h_time_unit not in unit_factors:
raise AnsibleFilterError( raise AnsibleFilterError(
"to_time_unit() can not interpret following string: %s" % human_time) "to_time_unit() can not interpret following string: %s" % human_time)
time_in_milliseconds = h_time_int * multiply(UNIT_FACTORS[h_time_unit]) time_in_milliseconds = h_time_int * multiply(unit_factors[h_time_unit])
result += time_in_milliseconds result += time_in_milliseconds
return round(result * divide(UNIT_FACTORS[unit]), 12) return round(result / multiply(unit_factors[unit]), 12)
def to_milliseconds(human_time): def to_milliseconds(human_time, **kwargs):
''' Return milli seconds from a human readable string ''' ''' Return milli seconds from a human readable string '''
return to_time_unit(human_time, 'ms') return to_time_unit(human_time, 'ms', **kwargs)
def to_seconds(human_time): def to_seconds(human_time, **kwargs):
''' Return seconds from a human readable string ''' ''' Return seconds from a human readable string '''
return to_time_unit(human_time, 's') return to_time_unit(human_time, 's', **kwargs)
def to_minutes(human_time): def to_minutes(human_time, **kwargs):
''' Return minutes from a human readable string ''' ''' Return minutes from a human readable string '''
return to_time_unit(human_time, 'm') return to_time_unit(human_time, 'm', **kwargs)
def to_hours(human_time): def to_hours(human_time, **kwargs):
''' Return hours from a human readable string ''' ''' Return hours from a human readable string '''
return to_time_unit(human_time, 'h') return to_time_unit(human_time, 'h', **kwargs)
def to_days(human_time): def to_days(human_time, **kwargs):
''' Return days from a human readable string ''' ''' Return days from a human readable string '''
return to_time_unit(human_time, 'd') return to_time_unit(human_time, 'd', **kwargs)
def to_weeks(human_time): def to_weeks(human_time, **kwargs):
''' Return weeks from a human readable string ''' ''' Return weeks from a human readable string '''
return to_time_unit(human_time, 'w') return to_time_unit(human_time, 'w', **kwargs)
def to_months(human_time): def to_months(human_time, **kwargs):
''' Return months from a human readable string ''' ''' Return months from a human readable string '''
return to_time_unit(human_time, 'mo') return to_time_unit(human_time, 'mo', **kwargs)
def to_years(human_time): def to_years(human_time, **kwargs):
''' Return years from a human readable string ''' ''' Return years from a human readable string '''
return to_time_unit(human_time, 'y') return to_time_unit(human_time, 'y', **kwargs)
class FilterModule(object): class FilterModule(object):

View file

@ -38,24 +38,29 @@
- "('1week' | community.general.to_days) == 7" - "('1week' | community.general.to_days) == 7"
- "('2weeks' | community.general.to_days) == 14" - "('2weeks' | community.general.to_days) == 14"
- "('1mo' | community.general.to_days) == 30" - "('1mo' | community.general.to_days) == 30"
- "('1mo' | community.general.to_days(month=28)) == 28"
- name: test to_weeks filter - name: test to_weeks filter
assert: assert:
that: that:
- "('1y' | community.general.to_weeks | int) == 52" - "('1y' | community.general.to_weeks | int) == 52"
- "('7d' | community.general.to_weeks) == 1" - "('7d' | community.general.to_weeks) == 1"
- "('1mo' | community.general.to_weeks(month=28)) == 4"
- name: test to_months filter - name: test to_months filter
assert: assert:
that: that:
- "('30d' | community.general.to_months) == 1" - "('30d' | community.general.to_months) == 1"
- "('1year' | community.general.to_months | int) == 12" - "('1year' | community.general.to_months | int) == 12"
- "('5years' | community.general.to_months(month=30, year=360)) == 60"
- "('1years' | community.general.to_months(month=2, year=34)) == 17"
- name: test to_years filter - name: test to_years filter
assert: assert:
that: that:
- "('365d' | community.general.to_years | int) == 1" - "('365d' | community.general.to_years | int) == 1"
- "('12mo' | community.general.to_years | round(0, 'ceil')) == 1" - "('12mo' | community.general.to_years | round(0, 'ceil')) == 1"
- "('24mo' | community.general.to_years(month=30, year=360)) == 2"
- name: test fail unknown unit - name: test fail unknown unit
debug: debug:
@ -80,3 +85,15 @@
that: that:
- res is failed - res is failed
- "'to_time_unit() can not interpret following string' in res.msg" - "'to_time_unit() can not interpret following string' in res.msg"
- name: test fail unknown kwarg
debug:
msg: "{{ '1s' | community.general.to_time_unit('s', second=23) }}"
ignore_errors: yes
register: res
- name: test fail unknown kwarg
assert:
that:
- res is failed
- "'to_time_unit() got unknown keyword arguments' in res.msg"