def test_none_cron_expression_error(self): options = Options() options.throw_exception_on_parse_error = False ceh = ExpressionDescriptor(None, options) self.assertEqual( "Field 'ExpressionDescriptor.expression' not found.", ceh.get_description(DescriptionTypeEnum.FULL))
def test_inline_import(self): from cron_descriptor import Options, DescriptionTypeEnum, ExpressionDescriptor options = Options() options.use_24hour_time_format = True ceh = ExpressionDescriptor("* * * * *", options) self.assertEqual("Every minute", ceh.get_description(DescriptionTypeEnum.FULL))
def test_invalid_cron_expression_error(self): options = Options() options.throw_exception_on_parse_error = False ceh = ExpressionDescriptor("INVALID CRON", options) self.assertEqual( "Error: Expression only has 2 parts. At least 5 part are required.", ceh.get_description(DescriptionTypeEnum.FULL))
def test_invalid_cron_expression_error(self): options = Options() options.throw_exception_on_parse_error = False ceh = ExpressionDescriptor("INVALID CRON", options) self.assertEqual( "Error: Expression only has 2 parts. At least 5 part are required.", ceh.get_description(DescriptionTypeEnum.FULL))
def test_title_casing(self): options = Options() options.casing_type = CasingTypeEnum.Title ceh = ExpressionDescriptor("* * * * *", options) self.assertEqual( "Every Minute", ceh.get_description(DescriptionTypeEnum.FULL))
def get_pretty(expression): import sys # By default the module is installed in the 2.7 branch, pyotherside uses python 3 # We use a custom location sys.path.append("/usr/share/harbour-sailcron/python/") # https://github.com/Salamek/cron-descriptor from cron_descriptor import Options, CasingTypeEnum, DescriptionTypeEnum, ExpressionDescriptor import subprocess # get proper 24/12 hour notation and strip output output = subprocess.check_output("/usr/bin/dconf read /sailfish/i18n/lc_timeformat24h", shell=True) output = str(output).replace("'", "").replace('b"', "").replace('\\n"', "").strip() if output == "24": is24h = True else: is24h = False # set options options = Options() options.throw_exception_on_parse_error = False options.casing_type = CasingTypeEnum.Sentence options.use_24hour_time_format = is24h descripter = ExpressionDescriptor(expression, options) human_format = descripter.get_description(DescriptionTypeEnum.FULL) return human_format
def test_full(self): options = Options() options.use_24hour_time_format = True ceh = ExpressionDescriptor("* * * * *", options) self.assertEqual( "Every minute", ceh.get_description(DescriptionTypeEnum.FULL))
def test_lower_casing(self): options = Options() options.casing_type = CasingTypeEnum.LowerCase ceh = ExpressionDescriptor("* * * * *", options) self.assertEqual( "every minute", ceh.get_description(DescriptionTypeEnum.FULL))
def test_inline_import(self): from cron_descriptor import Options, DescriptionTypeEnum, ExpressionDescriptor options = Options() options.use_24hour_time_format = True ceh = ExpressionDescriptor("* * * * *", options) self.assertEqual( "Every minute", ceh.get_description(DescriptionTypeEnum.FULL))
def test_full_import(self): from cron_descriptor.Options import Options from cron_descriptor.DescriptionTypeEnum import DescriptionTypeEnum from cron_descriptor.ExpressionDescriptor import ExpressionDescriptor options = Options() options.use_24hour_time_format = True ceh = ExpressionDescriptor("* * * * *", options) self.assertEqual('Every minute', ceh.get_description(DescriptionTypeEnum.FULL))
def test_full_import(self): from cron_descriptor.Options import Options from cron_descriptor.DescriptionTypeEnum import DescriptionTypeEnum from cron_descriptor.ExpressionDescriptor import ExpressionDescriptor options = Options() options.use_24hour_time_format = True ceh = ExpressionDescriptor("* * * * *", options) self.assertEqual( 'Every minute', ceh.get_description(DescriptionTypeEnum.FULL))
def cronIntervalToDescription(interval): """ Convert a crontab interval to a human readable format :param interval: crontab interval :type interval: str :return: readable format or None :rtype: str|None """ try: descriptor = ExpressionDescriptor(interval, use_24hour_time_format=True) return descriptor.get_description() except: return None
def description(self, **kw): """ Returns a description of the crontab's schedule (if available) **kw - Keyword arguments to pass to cron_descriptor (see docs) """ try: from cron_descriptor import ExpressionDescriptor except ImportError: raise ImportError("cron_descriptor not available. Please install"\ "cron_descriptor python module via pip or your package manager") exdesc = ExpressionDescriptor(self.slices.clean_render(), **kw) return exdesc.get_description()
def description(self, **kw): """ Returns a description of the crontab's schedule (if available) **kw - Keyword arguments to pass to cron_descriptor (see docs) """ try: from cron_descriptor import ExpressionDescriptor except ImportError: raise ImportError("cron_descriptor not available. Please install"\ "cron_descriptor python module via pip or your package manager") exdesc = ExpressionDescriptor(self.slices.clean_render(), **kw) return exdesc.get_description()
def __init__(self, cron: str, timezone: Timezone) -> None: self._expression = cron_presets.get(cron, cron) self._timezone = timezone descriptor = ExpressionDescriptor(expression=self._expression, casing_type=CasingTypeEnum.Sentence, use_24hour_time_format=True) try: # checking for more than 5 parameters in Cron and avoiding evaluation for now, # as Croniter has inconsistent evaluation with other libraries if len(croniter(self._expression).expanded) > 5: raise FormatException() interval_description = descriptor.get_description() except (CroniterBadCronError, FormatException, MissingFieldException): interval_description = "" self.description = interval_description
def format_cron_syntax_filter( cron_syntax: Union[str, None]) -> Union[str, None]: if cron_syntax: expression_descriptor = ExpressionDescriptor(cron_syntax) return str(expression_descriptor) return None
def create_modal(self, pcron, parsed_command): # explanation of parts you can use parts = table( tbody( tr(th('*'), td("any value")), tr(th(','), td("value list separator")), tr(th('-'), td("range of values")), tr(th('/'), td("step values")), tr(th('0-9'), td("numbers")) ), _style="padding:0px;" ) return str(Modal("modal_"+str(self.count), div( strong('explanation:'), div(ExpressionDescriptor(pcron, _options), _id="hr"+str(self.count), _class="human-readable"), strong('cron:'), input(_class="in_cron", _id="in_cron"+str(self.count), _type="text", _value=pcron), strong('command:'), input(_id="in_comm"+str(self.count), _type="text", _value=escape(parsed_command)), parts, button("Save"), button("Cancel", _class="del"), _class="text-editor" ) ))
def render_frequency(record): """Create the cron description.""" if not record.frequency: return '' return str( ExpressionDescriptor(record.frequency, casing_type=CasingTypeEnum.LowerCase))
def test_to_kargs(self): self.assertEqual( "At 17:17", str( ExpressionDescriptor("17 17 * * *", self.options, use_24hour_time_format=True)))
async def home(request): ctab = CrontabRenderer(str(crontab("-l"))) # last_edit = str(crontab("-v")) # try/catch htmlcal = calendar.HTMLCalendar(calendar.SUNDAY) cal = htmlcal.formatyear(2020,1) upt = str(uptime()) page = article( script(_src="/assets/js/later.min.js"), script(_src=domonic.JS_MASTER), link(_rel="stylesheet", _type="text/css", _href=domonic.CSS_STYLE), div( sub(str(date()), " ", a("🔄", _href="/")), h1("📅 ezcron"), _style="text-align:center;" ), div( div(ExpressionDescriptor("* * * * *", _options), _id="hr0", _class="human-readable"), input(_class="in_cron", _id="in_cron0", _type="text", _value="* * * * *"), _class="cron-input" ), h5(f"{ctab.count} cron jobs detected:"), div(str(ctab())), button("Add another"), h5("When the cron jobs are scheduled to run:"), div(cal), p(strong("uptime : "), upt), h5("Useful Links:"), a( "crontab guru", _href="https://crontab.guru/", _target="_blank") ) return response.html( render( Webpage(page, _dark_mode) ) )
def test_empty_cron_expression_exception(self): self.options.throw_exception_on_parse_error = True ceh = ExpressionDescriptor('', self.options) self.assertRaises( MissingFieldException, ceh.get_description, DescriptionTypeEnum.FULL)
def test_invalid_syntax_exception(self): self.options.throw_exception_on_parse_error = True ceh = ExpressionDescriptor("* $ * * *", self.options) self.assertRaises( FormatException, ceh.get_description, DescriptionTypeEnum.FULL)
def test_locale_de(self): options = Options() options.locale_code = 'de_DE' options.use_24hour_time_format = True self.assertEqual( "Jede Minute", ExpressionDescriptor("* * * * *", options).get_description())
def parse_expression(self): options = Options() options.throw_exception_on_parse_error = True options.casing_type = CasingTypeEnum.Sentence options.use_24hour_time_format = True return ExpressionDescriptor(self.expression, options).get_description( DescriptionTypeEnum.FULL)
def get_pretty(line_nbr, expression): """Get a human readable string for the cron expression""" import sys import subprocess import pyotherside # By default the module is installed in the 2.7 branch, pyotherside uses python 3 # We use a custom location sys.path.append("/usr/share/harbour-sailcron/python/") # https://github.com/Salamek/cron-descriptor from cron_descriptor import Options, CasingTypeEnum, DescriptionTypeEnum, ExpressionDescriptor # get proper 24/12 hour notation and strip output output = subprocess.check_output( "/usr/bin/dconf read /sailfish/i18n/lc_timeformat24h", shell=True) output = str(output).replace("'", "").replace('b"', "").replace('\\n"', "").strip() is24h = bool(output == "24") SPECIALS = { "reboot": '@reboot', "hourly": '0 * * * *', "daily": '0 0 * * *', "weekly": '0 0 * * 0', "monthly": '0 0 1 * *', "yearly": '0 0 1 1 *', "annually": '0 0 1 1 *', "midnight": '0 0 * * *' } key = expression.lstrip('@').rstrip(' ').lower() if key in SPECIALS.keys(): expression = SPECIALS[key] # set options options = Options() options.throw_exception_on_parse_error = False options.casing_type = CasingTypeEnum.Sentence options.use_24hour_time_format = is24h if expression == "@reboot": pyotherside.send('result', line_nbr, expression) human_format = "reboot" else: descripter = ExpressionDescriptor(expression, options) human_format = descripter.get_description(DescriptionTypeEnum.FULL) pyotherside.send('result', line_nbr, human_format) return human_format
def validate(self) -> bool: rv = Form.validate(self) if not rv: return False project_name_exists = PullMirror.query.filter_by( project_name=self.project_name.data).first() if project_name_exists: self.project_name.errors.append( gettext('Project name %(project_name)s already exists.', project_name=self.project_name.data)) return False project_mirror_exists = PullMirror.query.filter_by( project_mirror=self.project_mirror.data).first() if project_mirror_exists: self.project_mirror.errors.append( gettext('Project mirror %(project_mirror)s already exists.', project_mirror=self.project_mirror.data)) return False if not GitRemote.detect_vcs_type(self.project_mirror.data): self.project_mirror.errors.append( gettext('Unknown VCS type or detection failed.')) return False if not self.group.data: self.group.errors.append( gettext( 'You have to select GitLab group where mirrored project will be created.' )) return False try: check_project_visibility_in_group(self.visibility.data, self.group.data) except VisibilityError as e: self.visibility.errors.append(gettext(str(e))) return False if check_project_exists(self.project_name.data, self.group.data): if not self.is_force_create.data: self.project_name.errors.append( gettext( 'Project with name %(project_name)s already exists in selected group and "Create project in GitLab even if it already exists." is not checked in "Advanced options"', project_name=self.project_name.data)) return False if self.periodic_sync.data: try: ExpressionDescriptor(self.periodic_sync.data, throw_exception_on_parse_error=True) except (MissingFieldException, FormatException): self.periodic_sync.errors.append( gettext('Wrong cron expression.')) return True
def format_poll_data(poll: Poll): options = Options() options.locale_code = "ru_RU" return (poll.question or "Нет", ("\n\t\\- " + "\n\t\\- ".join(poll.answers)) if poll.answers else "Нет", "Да" if poll.is_anonymous else "Нет", "Да" if poll.is_multiple else "Нет", str(ExpressionDescriptor(poll.schedule, options)) if poll.schedule else "Не установлено")
def create_timedelta_string( ftime: datetime, frequency: str, utime: Optional[datetime] = None, ) -> Optional[str]: """Create a string rendering a time delta between now and the given one. The rendering proceeds gradually to see if the words days, hours, minutes etc. are needed. :param ftime: datetime object (may be in the past) :param frequency: string with the cron frequency (or empty) :param utime: until datetime object :return: String rendering """ diagnostic_msg = models.ScheduledOperation.validate_times( ftime, frequency, utime) if diagnostic_msg: return None now = datetime.now(pytz.timezone(settings.TIME_ZONE)) if ftime and not frequency and not utime: # Single execution if ftime < now and not utime: return None return ftime.strftime('%H:%M:%S %z %Y/%b/%d') # Repeating execution. result = str( ExpressionDescriptor(frequency, casing_type=CasingTypeEnum.LowerCase)) if not ftime and not utime: return result if ftime: # Has start time result = (ugettext('Starting at ') + ftime.strftime('%H:%M:%S %z %Y/%b/%d') + ', ' + result) if utime: # Has finish time result = result + ', until ' + utime.strftime('%H:%M:%S %z %Y/%b/%d') return result
def get_item_value_dictionary(sch_obj: models.ScheduledOperation) -> Dict: """Get a dictionary with the values in the time.""" result = model_to_dict(sch_obj) result['operation_type'] = models.Log.LOG_TYPES[result['operation_type']] if result['frequency']: result['frequency'] = str(ExpressionDescriptor(result['frequency'])) result['workflow'] = str(sch_obj.workflow) result['action'] = str(sch_obj.action) result['payload'] = json.dumps(result['payload'], indent=2) result.pop('id') result.pop('user') result = { models.ScheduledOperation._meta.get_field(key).verbose_name.title(): val for key, val in result.items() } return result
def __init__(self, cronfile): """Initialize CrontabReader Args: cronfile: Path to cronfile Returns: None """ options = Options() options.day_of_week_start_index_zero = False options.use_24hour_time_format = True with open(cronfile) as f: for line in f.readlines(): parsed_line = self.parse_cron_line(line) if parsed_line: print("{} -> {}".format( parsed_line, ExpressionDescriptor(parsed_line, options)))
def validate(self) -> bool: rv = Form.validate(self) if not rv: return False project_name_exists = PullMirror.query.filter( PullMirror.project_name == self.project_name.data, PullMirror.id != self.id.data).first() if project_name_exists: self.project_name.errors.append( gettext('Project name %(project_name)s already exists.', project_name=self.project_name.data)) return False project_mirror_exists = PullMirror.query.filter( PullMirror.project_mirror == self.project_mirror.data, PullMirror.id != self.id.data).first() if project_mirror_exists: self.project_mirror.errors.append( gettext('Project mirror %(project_mirror)s already exists.', project_mirror=self.project_mirror.data)) return False if not GitRemote.detect_vcs_type(self.project_mirror.data): self.project_mirror.errors.append( gettext('Unknown VCS type or detection failed.')) return False try: check_project_visibility_in_group(self.visibility.data, self.group.data) except VisibilityError as e: self.visibility.errors.append(gettext(str(e))) return False if self.periodic_sync.data: try: ExpressionDescriptor(self.periodic_sync.data, throw_exception_on_parse_error=True) except (MissingFieldException, FormatException): self.periodic_sync.errors.append( gettext('Wrong cron expression.')) return True
def print_line(self, parsed_line, parsed_command, line_number): hex = self.random_color() ref = 'modal_'+str(self.count) # the target modal return str( div( strong( parsed_line, _style=f'color:{hex};', _class="thecron"), " Runs: " + str(ExpressionDescriptor(parsed_line, _options)), " ", pre( escape(parsed_command) ), " ",button( "✏️ EDIT", **{'_data-ref':ref}, _class='open btn-sm' ), " ",button( "X DELETE", _class='del btn-sm', **{'_data-ref':ref}, _onclick="alert('Not Yet Implmented!');" ), " ",button( "🏃 RUN NOW", _class='go btn-sm', **{'_data-ref':ref}, _onclick=f"execute_order_66({line_number})"), div( "Next one will run at : "+self.get_next(parsed_line) ), strong( "Countdown:" ), div( _id="countdown"+str(self.count) ), # notice im changing the js interval var dynamicaly by appending the count to the id script(f'const timer{str(self.count)} = setInterval(showRemaining, 1000, "{self.get_next(parsed_line)}", "countdown{str(self.count)}", "timer{str(self.count)}" );'), hr() ) )
def test_lower_casing(self): self.options.casing_type = CasingTypeEnum.LowerCase ceh = ExpressionDescriptor("* * * * *", self.options) self.assertEqual("every minute", ceh.get_description(DescriptionTypeEnum.FULL))
def test_title_casing(self): self.options.casing_type = CasingTypeEnum.Title ceh = ExpressionDescriptor("* * * * *", self.options) self.assertEqual("Every Minute", ceh.get_description(DescriptionTypeEnum.FULL))
def test_to_repr(self): self.assertIsInstance(ExpressionDescriptor("* * * * *"), ExpressionDescriptor)
def test_to_str(self): self.assertEqual( "Every minute", str(ExpressionDescriptor("* * * * *")))
def test_default(self): self.assertEqual( "Every minute", ExpressionDescriptor("* * * * *").get_description())
def get_descricao(self, cron_expressao): descripter = ExpressionDescriptor(cron_expressao, self.options) return descripter.get_description()