Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/chrisspen/django-chroniker
Browse files Browse the repository at this point in the history
…into django_4_compatibility

� Conflicts:
�	chroniker/admin.py
�	chroniker/constants.py
�	chroniker/management/commands/cronserver.py
�	chroniker/models.py
  • Loading branch information
Siburg committed Jun 26, 2024
2 parents 9691210 + ef00232 commit 3c7537b
Show file tree
Hide file tree
Showing 16 changed files with 156 additions and 252 deletions.
40 changes: 40 additions & 0 deletions .github/workflows/django.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: Django CI

on:
push:
branches: [ "**" ]
# pull_request:
# branches: [ "**" ]

jobs:
test:
runs-on: ubuntu-latest

strategy:
matrix:
python-version: ["3.8"]

steps:
- name: Checkout code
uses: actions/checkout@v2

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}

- name: Install dependencies
run: |
sudo add-apt-repository -y ppa:deadsnakes/ppa
sudo apt-get -yq update
sudo apt-get -yq install python${{ matrix.python-version }} python${{ matrix.python-version }}-dev
python -m pip install --upgrade pip
pip install -r requirements-test.txt
- name: Run PEP8 script
run: |
chmod +x ./pep8.sh
./pep8.sh
- name: Run tests with Tox
run: tox
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Chroniker - Django Controlled Cron Jobs
=============================================================================

[![](https://img.shields.io/pypi/v/django-chroniker.svg)](https://pypi.python.org/pypi/django-chroniker) [![Build Status](https://img.shields.io/travis/chrisspen/django-chroniker.svg?branch=master)](https://travis-ci.org/chrisspen/django-chroniker) [![](https://pyup.io/repos/github/chrisspen/django-chroniker/shield.svg)](https://pyup.io/repos/github/chrisspen/django-chroniker)
[![](https://img.shields.io/pypi/v/django-chroniker.svg)](https://pypi.python.org/pypi/django-chroniker) [![Build Status](https://github.com/chrisspen/django-chroniker/actions/workflows/django.yml/badge.svg)](https://github.com/chrisspen/django-chroniker) [![](https://pyup.io/repos/github/chrisspen/django-chroniker/shield.svg)](https://pyup.io/repos/github/chrisspen/django-chroniker)

Overview
--------
Expand Down Expand Up @@ -210,13 +210,13 @@ To run all [tests](http://tox.readthedocs.org/en/latest/):

export TESTNAME=; tox

To run tests for a specific environment (e.g. Python 2.7 with Django 1.11):
To run tests for a specific environment (e.g. Python 3.8 with Django 3.0):

export TESTNAME=; tox -e py27-django111
export TESTNAME=; tox -e py38-django30

To run a specific test:

export TESTNAME=.testTimezone2; tox -e py36-django21
export TESTNAME=.testTimezone2; tox -e py38-django30

To run the [documentation server](http://www.mkdocs.org/#getting-started) locally:

Expand Down
42 changes: 14 additions & 28 deletions bin/chroniker
Original file line number Diff line number Diff line change
Expand Up @@ -15,33 +15,18 @@ logger = logging.getLogger('chroniker')
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description=('Run cron jobs for a Django '
'project using '
'django-chroniker.'),
'project using '
'django-chroniker.'),
epilog=("NOTE: You must provide one of "
"the following: settings or "
"project_dir."))
parser.add_argument(
'-s', metavar='settings', type=str, nargs='?',
dest="settings",
help=('Django settings module. You must provide.'))
parser.add_argument(
'-p', metavar='project_dir', type=str, nargs='?',
dest="project_dir", help='Path to project directory')
parser.add_argument(
'-e', metavar='virtualenv', type=str, nargs='?',
dest="virtualenv",
help=('Path to virtual environment "activate_this.py" file'))
parser.add_argument(
'-q', action='store_true', dest="quite", default=False,
help="Suppress output")
parser.add_argument(
'-l', action='store_true', dest="loud", default=False,
help="Display more output")
parser.add_argument(
'--jobs',
dest="jobs",
default='',
help='A comma-delimited list of job ids to limit executions to.')
"the following: settings or "
"project_dir.")
)
parser.add_argument('-s', metavar='settings', type=str, nargs='?', dest="settings", help=('Django settings module. You must provide.'))
parser.add_argument('-p', metavar='project_dir', type=str, nargs='?', dest="project_dir", help='Path to project directory')
parser.add_argument('-e', metavar='virtualenv', type=str, nargs='?', dest="virtualenv", help=('Path to virtual environment "activate_this.py" file'))
parser.add_argument('-q', action='store_true', dest="quite", default=False, help="Suppress output")
parser.add_argument('-l', action='store_true', dest="loud", default=False, help="Display more output")
parser.add_argument('--jobs', dest="jobs", default='', help='A comma-delimited list of job ids to limit executions to.')
args = parser.parse_args()

log_level = logging.INFO
Expand All @@ -58,7 +43,8 @@ if __name__ == "__main__":
if args.virtualenv:
virtualenv = os.path.abspath(args.virtualenv)
assert os.path.isfile(virtualenv), 'Virtualenv file "%s" does not exist.' % virtualenv
exec(open(virtualenv).read(), dict(__file__=virtualenv)) # pylint: disable=exec-used
with open(virtualenv, encoding='utf8') as fin:
exec(fin.read(), dict(__file__=virtualenv)) # pylint: disable=exec-used

# Now setup django
project_dir = args.project_dir
Expand All @@ -85,7 +71,7 @@ if __name__ == "__main__":
if settings:
os.environ['DJANGO_SETTINGS_MODULE'] = settings

jobs = args.jobs#(args.jobs or '').split(',')
jobs = args.jobs #(args.jobs or '').split(',')

logger.debug("Project dir: %s", project_dir)
logger.debug("Settings mod: %s", settings)
Expand Down
23 changes: 10 additions & 13 deletions chroniker/admin.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
from django import forms
from django.conf import settings
from django.urls import re_path as url
from django.contrib import admin
from django.core.management import get_commands
from django.urls import reverse, NoReverseMatch
from django.db import models
from django.forms import TextInput
from django.shortcuts import render
from django.urls import reverse, NoReverseMatch
try:
from django.urls import re_path
except ImportError:
from django.conf.urls import url as re_path
from django.utils.encoding import force_str
from django.utils.encoding import force_str as force_text
from django.http import HttpResponseRedirect, Http404, HttpResponse
from django.utils import dateformat, timezone
from django.utils.datastructures import MultiValueDict
Expand Down Expand Up @@ -367,7 +364,7 @@ def view_duration_graph(self, request, object_id):
media = self.media

context = {
'title': _('Change %s') % force_str(opts.verbose_name),
'title': _('Change %s') % force_text(opts.verbose_name),
'object_id': object_id,
'original': obj,
'is_popup': False,
Expand All @@ -384,9 +381,9 @@ def view_duration_graph(self, request, object_id):
def get_urls(self):
urls = super().get_urls()
my_urls = [
re_path(r'^(.+)/run/$', self.admin_site.admin_view(self.run_job_view), name="chroniker_job_run"),
re_path(r'^(.+)/stop/$', self.admin_site.admin_view(self.stop_job_view), name="chroniker_job_stop"),
re_path(r'^(.+)/graph/duration/$', self.admin_site.admin_view(self.view_duration_graph), name='chroniker_job_duration_graph'),
url(r'^(.+)/run/$', self.admin_site.admin_view(self.run_job_view), name="chroniker_job_run"),
url(r'^(.+)/stop/$', self.admin_site.admin_view(self.stop_job_view), name="chroniker_job_stop"),
url(r'^(.+)/graph/duration/$', self.admin_site.admin_view(self.view_duration_graph), name='chroniker_job_duration_graph'),
]
return my_urls + urls

Expand Down Expand Up @@ -559,8 +556,8 @@ def view_full_stderr(self, request, log_id):
def get_urls(self):
urls = super().get_urls()
my_urls = [
re_path(r'^(?P<log_id>[0-9]+)/stdout/?$', self.admin_site.admin_view(self.view_full_stdout), name='chroniker_log_stdout'),
re_path(r'^(?P<log_id>[0-9]+)/stderr/?$', self.admin_site.admin_view(self.view_full_stderr), name='chroniker_log_stderr'),
url(r'^(?P<log_id>[0-9]+)/stdout/?$', self.admin_site.admin_view(self.view_full_stdout), name='chroniker_log_stdout'),
url(r'^(?P<log_id>[0-9]+)/stderr/?$', self.admin_site.admin_view(self.view_full_stderr), name='chroniker_log_stderr'),
]
return my_urls + urls

Expand Down Expand Up @@ -690,7 +687,7 @@ def run_job_view(self, request, pk):
def get_urls(self):
urls = super().get_urls()
my_urls = [
re_path(r'^(.+)/run/$', self.admin_site.admin_view(self.run_job_view), name="chroniker_job_run"),
url(r'^(.+)/run/$', self.admin_site.admin_view(self.run_job_view), name="chroniker_job_run"),
]
return my_urls + urls

Expand Down
6 changes: 1 addition & 5 deletions chroniker/constants.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
try:
from django.utils.translation import gettext_lazy as _
except ImportError:
from django.utils.translation import ugettext_lazy as _

from django.utils.translation import gettext_lazy as _

YEARLY = 'YEARLY'
MONTHLY = 'MONTHLY'
Expand Down
41 changes: 4 additions & 37 deletions chroniker/management/commands/cron.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
from collections import defaultdict
from functools import partial
from multiprocessing import Queue
from optparse import make_option

import psutil

Expand Down Expand Up @@ -129,7 +128,7 @@ def run_cron(jobs=None, **kwargs):
pass
elif os.path.isfile(pid_fn):
try:
old_pid = int(open(pid_fn, 'r').read())
old_pid = int(open(pid_fn, 'r', encoding='utf8').read())
if utils.pid_exists(old_pid):
print('%s already exists, exiting' % pid_fn)
sys.exit()
Expand All @@ -139,7 +138,7 @@ def run_cron(jobs=None, **kwargs):
pass
except TypeError:
pass
open(pid_fn, 'w').write(pid)
open(pid_fn, 'w', encoding='utf8').write(pid)
clear_pid = True

procs = []
Expand Down Expand Up @@ -167,13 +166,13 @@ def run_cron(jobs=None, **kwargs):
Job.objects.update()
job = Job.objects.get(id=job.id)
if not force_run and not job.is_due_with_dependencies_met(running_ids=running_ids):
utils.smart_print(u'Job {} {} is due but has unmet dependencies.'\
utils.smart_print('Job {} {} is due but has unmet dependencies.'\
.format(job.id, job))
continue

# Immediately mark the job as running so the next jobs can
# update their dependency check.
utils.smart_print(u'Running job {} {}.'.format(job.id, job))
utils.smart_print('Running job {} {}.'.format(job.id, job))
running_ids.add(job.id)
if dryrun:
continue
Expand Down Expand Up @@ -270,38 +269,6 @@ def run_cron(jobs=None, **kwargs):

class Command(BaseCommand):
help = 'Runs all jobs that are due.'
option_list = getattr(BaseCommand, 'option_list', ()) + (
make_option('--update_heartbeat',
dest='update_heartbeat',
default=1,
help='If given, launches a thread to asynchronously update ' + \
'job heartbeat status.'),
make_option('--force_run',
dest='force_run',
action='store_true',
default=False,
help='If given, forces all jobs to run.'),
make_option('--dryrun',
action='store_true',
default=False,
help='If given, only displays jobs to be run.'),
make_option('--jobs',
dest='jobs',
default='',
help='A comma-delimited list of job ids to limit executions to.'),
make_option('--name',
dest='name',
default='',
help='A name to give this process.'),
make_option('--sync',
action='store_true',
default=False,
help='If given, runs jobs one at a time.'),
make_option('--verbose',
action='store_true',
default=False,
help='If given, shows debugging info.'),
)

def add_arguments(self, parser):
parser.add_argument('--update_heartbeat',
Expand Down
7 changes: 2 additions & 5 deletions chroniker/management/commands/cronserver.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,7 @@

from django.core.management.base import BaseCommand
from django.core.management import call_command
try:
from django.utils.translation import gettext_lazy as _
except ImportError:
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _

logger = logging.getLogger('chroniker.commands.cronserver')

Expand All @@ -24,7 +21,7 @@ def run(self):

class Command(BaseCommand):
args = "time"
help = _("Emulates a reoccurring cron call to run jobs at a specified " "interval. This is meant primarily for development use.")
help = _("Emulates a reoccurring cron call to run jobs at a specified interval. This is meant primarily for development use.")

def handle(self, *args, **options):

Expand Down
28 changes: 28 additions & 0 deletions chroniker/migrations/0004_auto_20240328_2035.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Generated by Django 3.2.23 on 2024-03-28 20:35

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('chroniker', '0003_auto_20200822_2026'),
]

operations = [
migrations.AlterField(
model_name='job',
name='id',
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
),
migrations.AlterField(
model_name='jobdependency',
name='id',
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
),
migrations.AlterField(
model_name='log',
name='id',
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
),
]
Loading

0 comments on commit 3c7537b

Please sign in to comment.