Skip to content

Commit

Permalink
Drop support for Python <= 3.7 (#229)
Browse files Browse the repository at this point in the history
* Drop support for Python <= 3.7

* Remove workaround for Python 2

* Remove workaround for Python 2

* Replace nose by nose2

* TOKEN is now required to upload the coverage report to codecov
  • Loading branch information
viniciuschiele authored May 17, 2023
1 parent b34362d commit 93cec4e
Show file tree
Hide file tree
Showing 10 changed files with 131 additions and 143 deletions.
2 changes: 1 addition & 1 deletion .coveragerc
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
[report]
show_missing = True
show_missing = True
6 changes: 4 additions & 2 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.7", "3.9"]
python-version: ["3.8", "3.9", "3.10", "3.11"]
steps:
- name: Git Clone
uses: actions/checkout@v3
Expand All @@ -22,6 +22,8 @@ jobs:
run: |
pip install -r requirements.txt
pip install -r test-requirements.txt
nosetests -v -l DEBUG --logging-level=DEBUG --with-coverage --cover-package=flask_apscheduler
nose2 -v
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
token: ${{secrets.CODECOV_TOKEN}}
36 changes: 18 additions & 18 deletions flask_apscheduler/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ def get_scheduler_info():
scheduler = current_app.apscheduler

d = OrderedDict([
('current_host', scheduler.host_name),
('allowed_hosts', scheduler.allowed_hosts),
('running', scheduler.running)
("current_host", scheduler.host_name),
("allowed_hosts", scheduler.allowed_hosts),
("running", scheduler.running)
])

return jsonify(d)
Expand Down Expand Up @@ -82,7 +82,7 @@ def shutdown_scheduler():

try:
data = request.get_json(silent=True, force=True) or {}
wait = data.get('wait') is not False
wait = data.get("wait") is not False

current_app.apscheduler.shutdown(wait=wait)
return Response(status=204)
Expand All @@ -101,8 +101,8 @@ def add_job():
job = current_app.apscheduler.add_job(**data)
return jsonify(job)
except ConflictingIdError:
logging.warning('Job %s already exists.' % data.get('id'))
return jsonify(dict(error_message='Job %s already exists.' % data.get('id')), status=409)
logging.warning(f"Job {data.get('id')} already exists.")
return jsonify(dict(error_message=f"Job {data.get('id')} already exists."), status=409)
except Exception as e:
logging.error(e, exc_info=True)
return jsonify(dict(error_message=str(e)), status=500)
Expand All @@ -115,8 +115,8 @@ def delete_job(job_id):
current_app.apscheduler.remove_job(job_id)
return Response(status=204)
except JobLookupError:
logging.warning('Job %s not found.' % job_id)
return jsonify(dict(error_message='Job %s not found' % job_id), status=404)
logging.warning(f"Job {job_id} not found.")
return jsonify(dict(error_message=f"Job {job_id} not found"), status=404)
except Exception as e:
logging.error(e, exc_info=True)
return jsonify(dict(error_message=str(e)), status=500)
Expand All @@ -128,8 +128,8 @@ def get_job(job_id):
job = current_app.apscheduler.get_job(job_id)

if not job:
logging.warning('Job %s not found.' % job_id)
return jsonify(dict(error_message='Job %s not found' % job_id), status=404)
logging.warning(f"Job {job_id} not found.")
return jsonify(dict(error_message=f"Job {job_id} not found"), status=404)

return jsonify(job)

Expand Down Expand Up @@ -157,8 +157,8 @@ def update_job(job_id):
job = current_app.apscheduler.get_job(job_id)
return jsonify(job)
except JobLookupError:
logging.warning('Job %s not found.' % job_id)
return jsonify(dict(error_message='Job %s not found' % job_id), status=404)
logging.warning(f"Job {job_id} not found.")
return jsonify(dict(error_message=f"Job {job_id} not found"), status=404)
except Exception as e:
logging.error(e, exc_info=True)
return jsonify(dict(error_message=str(e)), status=500)
Expand All @@ -172,8 +172,8 @@ def pause_job(job_id):
job = current_app.apscheduler.get_job(job_id)
return jsonify(job)
except JobLookupError:
logging.warning('Job %s not found.' % job_id)
return jsonify(dict(error_message='Job %s not found' % job_id), status=404)
logging.warning(f"Job {job_id} not found.")
return jsonify(dict(error_message=f"Job {job_id} not found"), status=404)
except Exception as e:
logging.error(e, exc_info=True)
return jsonify(dict(error_message=str(e)), status=500)
Expand All @@ -187,8 +187,8 @@ def resume_job(job_id):
job = current_app.apscheduler.get_job(job_id)
return jsonify(job)
except JobLookupError:
logging.warning('Job %s not found.' % job_id)
return jsonify(dict(error_message='Job %s not found' % job_id), status=404)
logging.warning(f"Job {job_id} not found.")
return jsonify(dict(error_message=f"Job {job_id} not found"), status=404)
except Exception as e:
logging.error(e, exc_info=True)
return jsonify(dict(error_message=str(e)), status=500)
Expand All @@ -202,8 +202,8 @@ def run_job(job_id):
job = current_app.apscheduler.get_job(job_id)
return jsonify(job)
except JobLookupError:
logging.warning('Job %s not found.' % job_id)
return jsonify(dict(error_message='Job %s not found' % job_id), status=404)
logging.warning(f"Job {job_id} not found.")
return jsonify(dict(error_message=f"Job {job_id} not found"), status=404)
except Exception as e:
logging.error(e, exc_info=True)
return jsonify(dict(error_message=str(e)), status=500)
8 changes: 4 additions & 4 deletions flask_apscheduler/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def get_authorization_header():
Return request's 'Authorization:' header as
a two-tuple of (type, info).
"""
header = request.environ.get('HTTP_AUTHORIZATION')
header = request.environ.get("HTTP_AUTHORIZATION")

if not header:
return None
Expand Down Expand Up @@ -77,7 +77,7 @@ class HTTPBasicAuth(HTTPAuth):
"""
HTTP Basic authentication.
"""
www_authenticate_realm = 'Authentication Required'
www_authenticate_realm = "Authentication Required"

def get_authorization(self):
"""
Expand All @@ -99,11 +99,11 @@ def get_authorization(self):
except Exception:
return None

return Authorization('basic', username=bytes_to_wsgi(username), password=bytes_to_wsgi(password))
return Authorization("basic", username=bytes_to_wsgi(username), password=bytes_to_wsgi(password))

def get_authenticate_header(self):
"""
Return the value of `WWW-Authenticate` header in a
`401 Unauthenticated` response.
"""
return 'Basic realm="%s"' % self.www_authenticate_realm
return f'Basic realm="{self.www_authenticate_realm}"'
2 changes: 1 addition & 1 deletion flask_apscheduler/json.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

def jsonify(data, status=None):
content = flask.current_app.json.dumps(data, default=_default)
return flask.current_app.response_class(content, status=status, mimetype='application/json')
return flask.current_app.response_class(content, status=status, mimetype="application/json")


def _default(obj):
Expand Down
83 changes: 41 additions & 42 deletions flask_apscheduler/scheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
from . import api
from .utils import fix_job_def, pop_trigger

LOGGER = logging.getLogger('flask_apscheduler')
LOGGER = logging.getLogger("flask_apscheduler")


class APScheduler(object):
Expand All @@ -38,11 +38,11 @@ def __init__(self, scheduler=None, app=None):
self._host_name = socket.gethostname().lower()
self._authentication_callback = None

self.allowed_hosts = ['*']
self.allowed_hosts = ["*"]
self.auth = None
self.api_enabled = False
self.api_prefix = '/scheduler'
self.endpoint_prefix = 'scheduler.'
self.api_prefix = "/scheduler"
self.endpoint_prefix = "scheduler."
self.app = None

if app:
Expand Down Expand Up @@ -96,9 +96,8 @@ def start(self, paused=False):
if get_debug_flag() and not werkzeug.serving.is_running_from_reloader():
return

if self.host_name not in self.allowed_hosts and '*' not in self.allowed_hosts:
LOGGER.debug('Host name %s is not allowed to start the APScheduler. Servers allowed: %s' %
(self.host_name, ','.join(self.allowed_hosts)))
if self.host_name not in self.allowed_hosts and "*" not in self.allowed_hosts:
LOGGER.debug(f"Host name {self.host_name} is not allowed to start the APScheduler. Servers allowed: {','.join(self.allowed_hosts)}")
return

self._scheduler.start(paused=paused)
Expand Down Expand Up @@ -158,9 +157,9 @@ def add_job(self, id, func, **kwargs):
"""

job_def = dict(kwargs)
job_def['id'] = id
job_def['func'] = func
job_def['name'] = job_def.get('name') or id
job_def["id"] = id
job_def["func"] = func
job_def["name"] = job_def.get("name") or id

fix_job_def(job_def)

Expand Down Expand Up @@ -218,7 +217,7 @@ def modify_job(self, id, jobstore=None, **changes):

fix_job_def(changes)

if 'trigger' in changes:
if "trigger" in changes:
trigger, trigger_args = pop_trigger(changes)
self._scheduler.reschedule_job(id, jobstore, trigger, **trigger_args)

Expand Down Expand Up @@ -270,39 +269,39 @@ def _load_config(self):
"""
options = dict()

job_stores = self.app.config.get('SCHEDULER_JOBSTORES')
job_stores = self.app.config.get("SCHEDULER_JOBSTORES")
if job_stores:
options['jobstores'] = job_stores
options["jobstores"] = job_stores

executors = self.app.config.get('SCHEDULER_EXECUTORS')
executors = self.app.config.get("SCHEDULER_EXECUTORS")
if executors:
options['executors'] = executors
options["executors"] = executors

job_defaults = self.app.config.get('SCHEDULER_JOB_DEFAULTS')
job_defaults = self.app.config.get("SCHEDULER_JOB_DEFAULTS")
if job_defaults:
options['job_defaults'] = job_defaults
options["job_defaults"] = job_defaults

timezone = self.app.config.get('SCHEDULER_TIMEZONE')
timezone = self.app.config.get("SCHEDULER_TIMEZONE")
if timezone:
options['timezone'] = timezone
options["timezone"] = timezone

self._scheduler.configure(**options)

self.auth = self.app.config.get('SCHEDULER_AUTH', self.auth)
self.api_enabled = self.app.config.get('SCHEDULER_VIEWS_ENABLED', self.api_enabled) # for compatibility reason
self.api_enabled = self.app.config.get('SCHEDULER_API_ENABLED', self.api_enabled)
self.api_prefix = self.app.config.get('SCHEDULER_API_PREFIX', self.api_prefix)
self.endpoint_prefix = self.app.config.get('SCHEDULER_ENDPOINT_PREFIX', self.endpoint_prefix)
self.allowed_hosts = self.app.config.get('SCHEDULER_ALLOWED_HOSTS', self.allowed_hosts)
self.auth = self.app.config.get("SCHEDULER_AUTH", self.auth)
self.api_enabled = self.app.config.get("SCHEDULER_VIEWS_ENABLED", self.api_enabled) # for compatibility reason
self.api_enabled = self.app.config.get("SCHEDULER_API_ENABLED", self.api_enabled)
self.api_prefix = self.app.config.get("SCHEDULER_API_PREFIX", self.api_prefix)
self.endpoint_prefix = self.app.config.get("SCHEDULER_ENDPOINT_PREFIX", self.endpoint_prefix)
self.allowed_hosts = self.app.config.get("SCHEDULER_ALLOWED_HOSTS", self.allowed_hosts)

def _load_jobs(self):
"""
Load the job definitions from the Flask configuration.
"""
jobs = self.app.config.get('SCHEDULER_JOBS')
jobs = self.app.config.get("SCHEDULER_JOBS")

if not jobs:
jobs = self.app.config.get('JOBS')
jobs = self.app.config.get("JOBS")

if jobs:
for job in jobs:
Expand All @@ -312,19 +311,19 @@ def _load_api(self):
"""
Add the routes for the scheduler API.
"""
self._add_url_route('get_scheduler_info', '', api.get_scheduler_info, 'GET')
self._add_url_route('pause_scheduler', '/pause', api.pause_scheduler, 'POST')
self._add_url_route('resume_scheduler', '/resume', api.resume_scheduler, 'POST')
self._add_url_route('start_scheduler', '/start', api.start_scheduler, 'POST')
self._add_url_route('shutdown_scheduler', '/shutdown', api.shutdown_scheduler, 'POST')
self._add_url_route('add_job', '/jobs', api.add_job, 'POST')
self._add_url_route('get_job', '/jobs/<job_id>', api.get_job, 'GET')
self._add_url_route('get_jobs', '/jobs', api.get_jobs, 'GET')
self._add_url_route('delete_job', '/jobs/<job_id>', api.delete_job, 'DELETE')
self._add_url_route('update_job', '/jobs/<job_id>', api.update_job, 'PATCH')
self._add_url_route('pause_job', '/jobs/<job_id>/pause', api.pause_job, 'POST')
self._add_url_route('resume_job', '/jobs/<job_id>/resume', api.resume_job, 'POST')
self._add_url_route('run_job', '/jobs/<job_id>/run', api.run_job, 'POST')
self._add_url_route("get_scheduler_info", "", api.get_scheduler_info, "GET")
self._add_url_route("pause_scheduler", "/pause", api.pause_scheduler, "POST")
self._add_url_route("resume_scheduler", "/resume", api.resume_scheduler, "POST")
self._add_url_route("start_scheduler", "/start", api.start_scheduler, "POST")
self._add_url_route("shutdown_scheduler", "/shutdown", api.shutdown_scheduler, "POST")
self._add_url_route("add_job", "/jobs", api.add_job, "POST")
self._add_url_route("get_job", "/jobs/<job_id>", api.get_job, "GET")
self._add_url_route("get_jobs", "/jobs", api.get_jobs, "GET")
self._add_url_route("delete_job", "/jobs/<job_id>", api.delete_job, "DELETE")
self._add_url_route("update_job", "/jobs/<job_id>", api.update_job, "PATCH")
self._add_url_route("pause_job", "/jobs/<job_id>/pause", api.pause_job, "POST")
self._add_url_route("resume_job", "/jobs/<job_id>/resume", api.resume_job, "POST")
self._add_url_route("run_job", "/jobs/<job_id>/run", api.run_job, "POST")

def _add_url_route(self, endpoint, rule, view_func, method):
"""
Expand Down Expand Up @@ -373,7 +372,7 @@ def _handle_authentication_error(self):
"""
Return an authentication error.
"""
response = make_response('Access Denied')
response.headers['WWW-Authenticate'] = self.auth.get_authenticate_header()
response = make_response("Access Denied")
response.headers["WWW-Authenticate"] = self.auth.get_authenticate_header()
response.status_code = 401
return response
Loading

0 comments on commit 93cec4e

Please sign in to comment.