Giter Site home page Giter Site logo

cron-descriptor's Introduction

Cron Descriptor

Python tests Donate

A Python library that converts cron expressions into human readable strings. Ported to Python from https://github.com/bradyholt/cron-expression-descriptor.

Author: Adam Schubert (https://www.salamek.cz)
Original Author & Credit: Brady Holt (http://www.geekytidbits.com)
License: MIT

Features

  • Supports all cron expression special characters including * / , - ? L W, #
  • Supports 5, 6 (w/ seconds or year), or 7 (w/ seconds and year) part cron expressions
  • Provides casing options (Sentence, Title, Lower, etc.)
  • Localization with support for 17 languages
  • Supports Python 2.7 - 3.10

Installation

Using PIP

pip install cron-descriptor

Usage example

Simple

from cron_descriptor import get_description, ExpressionDescriptor

print(get_description("* 2 3 * *"))

#OR

print(str(ExpressionDescriptor("* 2 3 * *")))

Advanced

# Consult Options.py/CasingTypeEnum.py/DescriptionTypeEnum.py for more info
from cron_descriptor import Options, CasingTypeEnum, DescriptionTypeEnum, ExpressionDescriptor

descriptor = ExpressionDescriptor(
    expression = "*/10 * * * *",
    casing_type = CasingTypeEnum.Sentence,
    use_24hour_time_format = True
)

# GetDescription uses DescriptionTypeEnum.FULL by default:
print(descriptor.get_description())
print("{}".format(descriptor))

# Or passing Options class as second argument:

options = Options()
options.casing_type = CasingTypeEnum.Sentence
options.use_24hour_time_format = True
descriptor = ExpressionDescriptor("*/10 * * * *", options)
print(descriptor.get_description(DescriptionTypeEnum.FULL))

Languages Available

Language Locale Code Contributor
English en Brady Holt
Brazilian pt_PT Renato Lima
Chinese Simplified zh_CN Star Peng
Spanish es_ES Ivan Santos
Norwegian nb_NO Siarhei Khalipski
Turkish tr_TR Mustafa SADEDİL
Dutch nl_NL TotalMace
Russian ru_RU LbISS
French fr_FR Arnaud TAMAILLON
German de_DE Michael Schuler
Ukrainian uk_UA Taras
Italian it_IT rinaldihno
Czech cs_CZ Adam Schubert
Swedish sv_SE Åke Engelbrektson
Tamil ta_IN Sankar Hari
Persian fa_IR M. Yas. Davoodeh
Korean ko_KR KyuJoo Han
Japanese ja_JP Tho Nguyen

Original Source

Ports

Running Unit Tests

python setup.py test

Translating

cron-descriptor is using Gettext for translations.

To create new translation or edit existing one, i suggest using Poedit.

You can copy/rename and translate any file from locale directory:

cp ./cron_descriptor/locale/de_DE.po ./cron_descriptor/locale/YOUR_LOCALE_CODE.po
poedit ./cron_descriptor/locale/YOUR_LOCALE_CODE.po

or you can generate new untranslated *.po file from sources by running in cron_descriptor directory:

cd cron_descriptor
xgettext *.py -o locale/YOUR_LOCALE_CODE.po

Generating *.mo file from *.po file. In root directory run command:

msgfmt -o cron_descriptor/locale/YOUR_LOCALE_CODE.mo cron_descriptor/locale/YOUR_LOCALE_CODE.po

Developing

All suggestions and PR's are welcomed

Just clone this repository and register pre-commit hook by running:

ln -s ../../pre-commit.sh .git/hooks/pre-commit

Then install dev requirements:

pip install ruff

cron-descriptor's People

Contributors

adamchainz avatar agutierrezdapda avatar borgrabbit avatar borogum avatar bradymholt avatar bxdoan avatar cclauss avatar davoodeh avatar eduardomezencio avatar eriktelepovsky avatar erikvdven avatar eson57 avatar guysoft avatar hanqyu avatar pengwk avatar salamek avatar sankarhari avatar timrodz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cron-descriptor's Issues

Error installing 1.2.9 on pyhton 3.4

Hey,
Installing on a raspberrypi raspbian I get:

From pip3 install -r requirements.txt

Downloading/unpacking cron-descriptor (from -r requirements.txt (line 6))
  Downloading cron_descriptor-1.2.9.tar.gz
  Running setup.py (path:/tmp/pip-build-m6nvvpb9/cron-descriptor/setup.py) egg_info for package cron-descriptor
    Traceback (most recent call last):
      File "<string>", line 17, in <module>
      File "/tmp/pip-build-m6nvvpb9/cron-descriptor/setup.py", line 30, in <module>
        long_description=open('README.md').read(),
      File "/usr/lib/python3.4/encodings/ascii.py", line 26, in decode
        return codecs.ascii_decode(input, self.errors)[0]
    UnicodeDecodeError: 'ascii' codec can't decode byte 0xc4 in position 2514: ordinal not in range(128)
    Complete output from command python setup.py egg_info:
    Traceback (most recent call last):

  File "<string>", line 17, in <module>

  File "/tmp/pip-build-m6nvvpb9/cron-descriptor/setup.py", line 30, in <module>

    long_description=open('README.md').read(),

  File "/usr/lib/python3.4/encodings/ascii.py", line 26, in decode

    return codecs.ascii_decode(input, self.errors)[0]

UnicodeDecodeError: 'ascii' codec can't decode byte 0xc4 in position 2514: ordinal not in range(128)

----------------------------------------
Cleaning up...


Official Python 3.6 Support

I can't see anything that would cause an incompatibility with Python 3.6 and all the tests pass when ran against 3.6.7.
Mind bumping the maximum supported version?

There are errors in the Chinese translation

from cron_descriptor import get_description

cron_express = "30 */6 * 1,2,3 1-5"
print(get_description(cron_express))
在每小时的 30 分, 每 6 小时, Monday 到 Friday, 仅在 January, February, 和 March

As we can see, there is a mixture of Chinese and English

issue in translating day of week combination

Hi Salamek,

I noticed the combination of individual weekdays and a range leads to syntax errors:

>>> from cron_descriptor import get_description, ExpressionDescriptor
>>> print(get_description("38 20 * * 0,2,3-6"))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/site-packages/cron_descriptor/ExpressionDescriptor.py", line 568, in get_description
    return descripter.get_description(DescriptionTypeEnum.FULL)
  File "/usr/lib/python2.7/site-packages/cron_descriptor/ExpressionDescriptor.py", line 101, in get_description
    description = choices.get(description_type, self.get_seconds_description)()
  File "/usr/lib/python2.7/site-packages/cron_descriptor/ExpressionDescriptor.py", line 151, in get_full_description
    raise FormatException(description)
cron_descriptor.Exception.FormatException: An error occured when generating the expression description.  Check the cron expression syntax.

Just ranges or individual weekdays do work ok.

Parsing of cron expression with both range and individual hour fails

Possibly same issue as #6, but with hours rather than days.

>>> from cron_descriptor import get_description, ExpressionDescriptor
>>> print(get_description("15 6,10-20 * * *"))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "cron-descriptor-test/env/local/lib/python2.7/site-packages/cron_descriptor/ExpressionDescriptor.py", line 582, in get_description
    return descripter.get_description(DescriptionTypeEnum.FULL)
  File "cron-descriptor-test/env/local/lib/python2.7/site-packages/cron_descriptor/ExpressionDescriptor.py", line 101, in get_description
    description = choices.get(description_type, self.get_seconds_description)()
  File "cron-descriptor-test/env/local/lib/python2.7/site-packages/cron_descriptor/ExpressionDescriptor.py", line 149, in get_full_description

Incorrect description for (22 26 18 ? JAN,DEC WED#1,2 *)

Code:

from cron_descriptor import get_description, ExpressionDescriptor

print(get_description("22 26 18 ? JAN,DEC WED#1,1,2,3,4 *"))

Result: At 06:26:22 PM, on the None Wednesday, Monday, Tuesday, Wednesday, and Thursday of the month, only in January and December

Expected result: At 06:26:22 PM, on the first Wednesday, Monday, Tuesday, Wednesday, and Thursday of the month, only in January and December

Out-of-range and incorrect values allowed

Seems like bad values like a >60 in seconds or minutes, >23 in hours, etc. are just accepted.
Also, bogus values are just parsed as-is.

Shouldn't the descriptor throw an error for these?

Thanks

In [9]: get_description("*40 * * * *")
Out[9]: 'At *40 minutes past the hour'

In [10]: get_description("*foobar * * * *")
Out[10]: 'At *foobar minutes past the hour'

In [11]: get_description("foobar * * * *")
Out[11]: 'At foobar minutes past the hour'

In [13]: get_description("*123123123 * * * *")
Out[13]: 'At *123123123 minutes past the hour'

In [14]: get_description("123123123 * * * *")
Out[14]: 'At 123123123 minutes past the hour'

In [15]: get_description("123123123 * * * * *")
Out[15]: 'At 123123123 seconds past the minute'

Korean Translation missing mo file.

locale folder doesn't have a .mo file for ko_KR locale.( which makes module doesn't accept the locale code)

I've converted ko_KR.po -> ko_KR.mo file and added to locale folder
and when I tested with following code it works without any problem.

from cron_descriptor import get_description, Options


if __name__ in '__main__':
    options = Options()
    expr_ls = [
        '0 30 3,9,14,16,19,23 ? * SAT-SUN *'
        , '0 0 16 ? * SAT *'
        , '0 0 23 1/1 * ? *'
        , '0 20 3,9,14,16,19,23 ? * SAT-SUN *'
        , '0 0/1 * 1/1 * ? *'
        , '0 0,30 15,16,17,18,19,20,21,22,23,1,2,3 1/1 * ? *'
        , '0 0/15 * 1/1 * ? *'
    ]
    options.locale_code = 'ko_KR'
    for expr in expr_ls:
        print(get_description(expr, options))

    options.locale_code = 'cs_CZ'
    for expr in expr_ls:
        print(get_description(expr, options))

I suspect .mo file got filtered out by ignore list when it was pushed.
Would it be possible for me to make PR?

issue with bad cron entries

Hello, I was wondering if you can possibly help me figure out the best way to avoid bad cron entries like this one:"3-59/10 * * * 1-7" the code bombs out and it does not continue processing. is there a way for me to improve the code on my side to avoid this issue? perhaps I can improve the for loop to avoid processing a bad entry like the example I provided?
any help is greatly appreciated and thank you so much for this amazing library, it is so important!

here is the code I using:

#!/usr/bin/env python
import csv
import sys

from cron_descriptor import ExpressionDescriptor, Options, DescriptionTypeEnum, CasingTypeEnum

expressionField = "cron_expression"
humanReadableField = "cron_human_readable"

def main():
infile = sys.stdin
outfile = sys.stdout

r = csv.DictReader(infile)
header = r.fieldnames

w = csv.DictWriter(outfile, r.fieldnames)
w.writeheader()

options = Options()
options.verbose = True
options.throw_exception_on_parse_error = True
options.casing_type = CasingTypeEnum.Sentence

for result in r:
    cron_expression = result[expressionField]
    descripter = ExpressionDescriptor(cron_expression, options)
    result[humanReadableField] = str(descripter.get_description(DescriptionTypeEnum.FULL))
    w.writerow(result)

main()

Weekdays not localized

Hi Salamek,

I noticed the weekdays are not translated, while the rest of the string is. I made a small modification to get a localized day of week returned. I did not make a pull request as it is very small and perhaps you prefer a different solution.
Tools.py:

from .Exception import WrongArgumentException
from calendar import day_name


def number_to_day(day_number):
    """Returns day name by its number

    Args:
        day_number: Number of a day
    Returns:
        Day corresponding to day_number
    Raises:
        IndexError: When day_number is not found
    """
    return [day_name[6], day_name[0], day_name[1], day_name[2], day_name[3], day_name[4], day_name[5]][day_number]

number_to_month also return hard coded strings, but I do not see those returned in the results (always full month names).

Days of the week and months need to be upper cased.

See new code with upper() below.
# convert SUN-SAT format to 0-6 format
for day_number in self._cron_days:
expression_parts[5] = expression_parts[5].upper()
expression_parts[5] = expression_parts[5].replace(self._cron_days[day_number], str(day_number))

    # convert JAN-DEC format to 1-12 format
    for month_number in self._cron_months:
        expression_parts[4] = expression_parts[4].upper()
        expression_parts[4] = expression_parts[4].replace(self._cron_months[month_number], str(month_number))

I fixed my code by upper casing the cron expression before calling your excellent code. Thanks.

  • Rick -

Inconsistent licensing ?

The project is MIT license but some of the code has headers look like GPL:
https://github.com/Salamek/cron-descriptor/blob/master/cron_descriptor/ExpressionParser.py

Would you please help clarify if the project is entirely MIT licensed, with GPL license headers included in error?
Or is the project GPL licensed, with the contents of the LICENSE file being in error?
Or is the project partly MIT-licensed and partly GPL-licensed, without the differently-licensed files being segregated?

Thanks for your help

pip installs without locale folder

Hi!
Glad to see nice project here!!
I want to use cron-descriptor out from box, but have one trouble.
When i "pip install cron-descriptor" there are no locale folder in my installed env.

(test) danis@user:/tmp$ pip install cron_descriptor
(test) danis@user:~/.virtualenvs/test$ ll lib/python2.7/site-packages/cron_descriptor
total 128
drwxrwxr-x  2 danis danis  4096 сен  6 11:06 ./
drwxrwxr-x 25 danis danis  4096 сен  6 11:06 ../
-rw-rw-r--  1 danis danis   858 сен  6 11:06 CasingTypeEnum.py
-rw-rw-r--  1 danis danis   558 сен  6 11:06 CasingTypeEnum.pyc
-rw-rw-r--  1 danis danis   920 сен  6 11:06 DescriptionTypeEnum.py
-rw-rw-r--  1 danis danis   679 сен  6 11:06 DescriptionTypeEnum.pyc
-rw-rw-r--  1 danis danis  1304 сен  6 11:06 Exception.py
-rw-rw-r--  1 danis danis  1411 сен  6 11:06 Exception.pyc
-rw-rw-r--  1 danis danis 21663 сен  6 11:06 ExpressionDescriptor.py
-rw-rw-r--  1 danis danis 23261 сен  6 11:06 ExpressionDescriptor.pyc
-rw-rw-r--  1 danis danis  6579 сен  6 11:06 ExpressionParser.py
-rw-rw-r--  1 danis danis  4504 сен  6 11:06 ExpressionParser.pyc
-rw-rw-r--  1 danis danis  1277 сен  6 11:06 GetText.py
-rw-rw-r--  1 danis danis  1154 сен  6 11:06 GetText.pyc
-rw-rw-r--  1 danis danis  1171 сен  6 11:06 __init__.py
-rw-rw-r--  1 danis danis   601 сен  6 11:06 __init__.pyc
-rw-rw-r--  1 danis danis  1265 сен  6 11:06 Options.py
-rw-rw-r--  1 danis danis  1127 сен  6 11:06 Options.pyc
-rw-rw-r--  1 danis danis  1206 сен  6 11:06 StringBuilder.py
-rw-rw-r--  1 danis danis  1411 сен  6 11:06 StringBuilder.pyc

So no locale folder at all. And no localization for me.
Is there any special reason for behavior like that?
I can pull request, to port locale folder if you want.

PS
Installed version - 1.2.5
Python - 2.7.12
The tar file with lib contains locale folder, but it is not copied in installation directory.

Supporting timezones

Supporting timezones would be nice.

I have some system running with UTC, but crontabs should be represented on a central console running on CET (that is +0100).
I know implementing timezones may be tricky under some circumstances, such as "* 0-7,19-23 * * *".

GitHub vs PyPI

GitHub releases has v1.2.23 , but PyPI only has 1.2.21

Sunday is not normalized

For DayOfWeekStartIndexZero=True, the value of 7 should be normalized to 0. If not, you will get an error.

Error parsing day-of-month combined with day-of-week

Hello. Thank you very much for this library. It seems to be working well, except for a couple of corner-case issues. Here's some code:

import cron_descriptor
cron = '30 4 1,15 * FRI'
print(f'Description for [{cron}] is: {cron_descriptor.get_description(cron)}')

Output:

Description for [30 4 1,15 * FRI] is: At 04:30 AM, on day 1 and 15 of the month, only on Friday

This should actually be something like:

Description for [30 4 1,15 * FRI] is: At 04:30 AM, on day 1 and 15 of the month, plus every Friday

This is in keeping with the crontab(5) man page which indicates the day-of-month and day-of-week criteria should be combined with OR rather than AND.

Note: The day of a command's execution can be specified by two fields — day of month, and day of week. If both fields are restricted (i.e., aren't *), the command will be run when either field matches the current time. For example,
``30 4 1,15 * 5'' would cause a command to be run at 4:30 am on the 1st and 15th of each month, plus every Friday.

However, there is an exception to this due to a bug in Vixie cron/ISC cron/cronie. Because cron fails to parse asterisk fields that contain more than just a single asterisk (for example, */2), it will join the criteria together with AND rather than OR for those entries, in violation of its own man page. So for this code:

cron = '30 4 */2 * FRI'
print(f'Description for [{cron}] is: {cron_descriptor.get_description(cron)}')

cron-descriptor actually evaluates the code the same way the buggy cron does:

Description for [30 4 */2 * FRI] is: At 04:30 AM, every 2 days, only on Friday

(more details on the asterisk bug in cron is here: https://crontab.guru/cron-bug.html The consensus seems to be that this bug should not be fixed due to its having been around for decades now.)

So, could the incorrect evaluation of cron entries like "30 4 1,5 * FRI" be fixed, while still keeping consistency with the buggy versions of cron for entries like "30 4 */2 * FRI"?

Thanks for looking into it, and for your work on this tool.

Tests not excluded from install.

I'm attempting to make a Gentoo Ebuild for cron-descriptor-1.2.20. I'm only making use of the distutils-r1 eclass and it's interface for setuptools. This default setup forbids 'tests' packages from being installed.

  • ERROR: dev-python/cron_descriptor-1.2.20::overlay failed (install phase):
  • Package installs 'tests' package which is forbidden and likely a bug in the build system.

I am fairly inexperienced at this, but based on other packages, it is fairly standard that 'tests' be excluded from the setuptools packages.

I believe this to be a small bug with setup.py

Description for "0 0-13 * * *" could be improved

This code

from cron_descriptor import get_description
get_description("0 0-13 * * *")

returns

"Between 12:00 AM and 01:59 PM"

That's not wrong, but there is missing information.
A better description would be:

At minute 0 past every hour from 0 through 13.

(got from crontab.guru)

Translation files (.po) not in UTF-8

I am having trouble displaying all languages in a proper way. The content of the PO files seems to be a variation of ASCII encodings in UTF-8 format. Encoding them in real UTF-8 would solve all those issues I think.

Add a __main__.py

We could add a main.py to this project so that you would be able to run it in the terminal like:

> python -m cron_descriptor '* * * * *'
Every minute

Italian translation improvements

The italian translation may not be perfect in certain circumstances.

E.g., "* 0-7,19-23 * * *" would returns:

Ogni minuto, alle 00:00 al 07:59 e 19:00 al 23:59

I've used the following snippet:

import cron_descriptor
descripter = cron_descriptor.ExpressionDescriptor("* 0-7,19-23 * * *", use_24hour_time_format=True, locale_code='it_IT')
print(descripter.get_description())

The correct result should be:

Ogni minuto, dalle 00:00 alle 07:59 e dalle 19:00 alle 23:59

This can be obtained modifying the it_IT.po as follows:

# diff -ruN it_IT.po.orig it_IT.po
--- it_IT.po.orig       2019-01-17 11:24:15.033002345 +0100
+++ it_IT.po    2019-01-17 11:25:45.237514411 +0100
@@ -96,7 +96,7 @@
 #: ExpressionDescriptor.py:218
 #, python-brace-format
 msgid "at {0}"
-msgstr "alle {0}"
+msgstr "dalle {0}"

 #: ExpressionDescriptor.py:241
 msgid "first"
@@ -151,7 +151,7 @@
 #: ExpressionDescriptor.py:318
 #, python-brace-format
 msgid ", {0} through {1}"
-msgstr ", {0} al {1}"
+msgstr ", {0} alle {1}"

 #: ExpressionDescriptor.py:272
 #, python-brace-format
@@ -207,7 +207,7 @@

 #: ExpressionDescriptor.py:385
 msgid " and "
-msgstr " e "
+msgstr " e dalle "

 #: ExpressionDescriptor.py:433
 msgid ", every minute"

But I think that this would lead to errors in other circumstances (e.g. "0,30 6-17 * * *").
That's why using the "between {0} and {1}" syntax as follows should be a better option:

Ogni minuto, tra le 00:00 e le 07:59 e tra le 19:00 e le 23:59

Deprecation warning with Pip 22.3.1

When doing pip install cron-descriptor the following deprecation warning appears:

DEPRECATION: cron-descriptor is being installed using the legacy 'setup.py install' method, because it does not have a 'pyproject.toml' and the 'wheel' package is not installed. pip 23.1 will enforce this behaviour change. A possible replacement is to enable the '--use-pep517' option. Discussion can be found at pypa/pip#8559

6 part expression parsing incompatible with parse-crontab

The way this module parses 6 part Cron expressions is incompatible with other heavily used Python modules like parse-crontab.

For example, the following Expression "* * * * * *" is described as "Every second" while parse-crontab treats it as "Every minute". This is because parse-crontab assumes the 6th star in this case is the year (and thus the expression contains minutes, hours, ..., years), while this module requires a 4 digit number in that slot to make the same assumption (and otherwise, assumes this is an expression containing seconds).

I'd like to suggest adding an option that would adopt the parsing convention of parse-crontab and thus make this module more compatible with other Python modules.

I'm happy to make the change and submit a PR.

archlinux PKGBUILD

Hi there,

You got a PKGBUILD in your project which is super nice.
Mind throwing that into the AUR?

If you don't feel like it, I could do that as well and maintain updates etc.

Incorrect range accepted

Salamek,

De following string is accepted:

print(get_description("* * * * 6-3"))
Every minute, Saturday through Wednesday

That interpretation looks fine, but I was not able to find any cron flavour that would actually support a range starting with a higher start-value than end-value (although in this case this feature would have been a nice to have).

Calling some functions of ExpressionDescriptor first requires calling get_description.

I have a use case where I am trying to add on to your ExpressionDescriptor.get_full_description method so that I can omit any arbitrary component of the humanreadable expression (in my case, the time_segment).

In order to do so, I have chosen to extend your ExpressionDescriptor class and add my omission function. This is partially because I also need to account for some irregularities that come up when you start ripping pieces of the expression out willy-nilly. I figured this could also be done with Options, but it looked like it would be a lot more work.

However, I found I have IndexErrors with _expression_parts if I try to call get_time_of_day_description, get_day_of_month_description, get_month_description, get_day_of_week_description, or get_year_description in my function.

I also found that I can call get_description first (either the exported function or ExpressionDescriptor itself) and then I no longer get exceptions when calling my function from my ExpressionDescriptor instance.

This is probably because parsing the expression and then setting the _expression_parts are the first behaviours in the ExpressionDescriptor.get_description function.

I would argue that it is appropriate to parse in the __init__ function for the class, because the expression parts seem needed for quite a few other functions of the class.

If there is a good reason to not set the parser in the __init__ function, then I would request that the ExpressionParser class be made available as part of the package so that anyone can call the parser as needed.

"2-59/3 1 * * *" not supported

"2-59/3 1 * * *" not supported, however "2-59/3 1,9 * * *" is ok.

I have very limited cron expression experience so hopefully this is a valid expression and I'm not wasting people's time.

Specific time every day, not showing "Every day"

Like this expression ExpressionDescriptor.GetDescription("* * * * 4L"); shows a full description like:

"Every minute, on the last Thursday of the month"

I actually expect this expression ExpressionDescriptor.GetDescription("30 02 14 * * *"); to show

"Every day at 02:02:30 PM"

instead of

"At 02:02:30 PM"

Anyone who is already familiar with this package and knows how to update this one?

Fails to parse crontab with full day of week name

Originally reported at celery/django-celery-beat#647

Having crontab 0 2 * * monday leads to an exception (FormatException: null):

Traceback (most recent call last):
  File "/home/weblate/weblate-env/lib/python3.9/site-packages/cron_descriptor/ExpressionDescriptor.py", line 131, in get_full_description
    day_of_week_desc = self.get_day_of_week_description()
  File "/home/weblate/weblate-env/lib/python3.9/site-packages/cron_descriptor/ExpressionDescriptor.py", line 342, in get_day_of_week_description
    return self.get_segment_description(
  File "/home/weblate/weblate-env/lib/python3.9/site-packages/cron_descriptor/ExpressionDescriptor.py", line 467, in get_segment_description
    description = get_description_format(expression).format(get_single_item_description(expression))
  File "/home/weblate/weblate-env/lib/python3.9/site-packages/cron_descriptor/ExpressionDescriptor.py", line 345, in <lambda>
    lambda s: get_day_name(s),
  File "/home/weblate/weblate-env/lib/python3.9/site-packages/cron_descriptor/ExpressionDescriptor.py", line 315, in get_day_name
    return ExpressionDescriptor.number_to_day(int(exp))

During handling of the above exception (invalid literal for int() with base 10: '1DAY'), another exception occurred:
  File "/home/weblate/weblate-env/lib/python3.9/site-packages/django/core/handlers/exception.py", line 56, in inner
    response = get_response(request)
  File "/home/weblate/weblate-env/lib/python3.9/site-packages/django/core/handlers/base.py", line 197, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/home/weblate/weblate-env/lib/python3.9/site-packages/sentry_sdk/integrations/django/views.py", line 85, in sentry_wrapped_callback
    return callback(request, *args, **kwargs)
  File "/home/weblate/weblate-env/lib/python3.9/site-packages/django/contrib/admin/options.py", line 686, in wrapper
    return self.admin_site.admin_view(view)(*args, **kwargs)
  File "/home/weblate/weblate-env/lib/python3.9/site-packages/django/utils/decorators.py", line 134, in _wrapped_view
    response = view_func(request, *args, **kwargs)
  File "/home/weblate/weblate-env/lib/python3.9/site-packages/django/views/decorators/cache.py", line 62, in _wrapped_view_func
    response = view_func(request, *args, **kwargs)
  File "/home/weblate/weblate-env/lib/python3.9/site-packages/django/contrib/admin/sites.py", line 242, in inner
    return view(request, *args, **kwargs)
  File "/home/weblate/weblate-env/lib/python3.9/site-packages/django/contrib/admin/options.py", line 1894, in change_view
    return self.changeform_view(request, object_id, form_url, extra_context)
  File "/home/weblate/weblate-env/lib/python3.9/site-packages/django_celery_beat/admin.py", line 155, in changeform_view
    crontab_dict[crontab.id] = crontab.human_readable
  File "/home/weblate/weblate-env/lib/python3.9/site-packages/django_celery_beat/models.py", line 319, in human_readable
    human_readable = get_description('{} {} {} {} {}'.format(
  File "/home/weblate/weblate-env/lib/python3.9/site-packages/cron_descriptor/ExpressionDescriptor.py", line 664, in get_description
    return descripter.get_description(DescriptionTypeEnum.FULL)
  File "/home/weblate/weblate-env/lib/python3.9/site-packages/cron_descriptor/ExpressionDescriptor.py", line 108, in get_description
    description = choices.get(description_type, self.get_seconds_description)()
  File "/home/weblate/weblate-env/lib/python3.9/site-packages/cron_descriptor/ExpressionDescriptor.py", line 148, in get_full_description
    raise FormatException(description)

The following code handles mon fine, but turns monday into 1DAY:

# convert SUN-SAT format to 0-6 format
for day_number in self._cron_days:
expression_parts[5] = expression_parts[5].upper().replace(self._cron_days[day_number], str(day_number))

That later fails in conversion to int. The conversion in celery works the other way – it extracts the first three letters of the string and uses that to convert to the int:

https://github.com/celery/celery/blob/3ce5b85806104e14f75a377fadc4de3e50038396/celery/utils/time.py#L215-L227

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.