avoid deprecated datetime.utcnow

deprecated in Python 3.12

replace with equivalent utils.utcnow(with_tz=False)
This commit is contained in:
Min RK
2023-12-19 14:47:35 +01:00
parent ab82b8e492
commit be14baf096
12 changed files with 57 additions and 36 deletions

View File

@@ -12,17 +12,21 @@ branch_labels = None
depends_on = None
from datetime import datetime
from datetime import datetime, timezone
import sqlalchemy as sa
from alembic import op
def utcnow():
return datetime.now(timezone.utc)._replace(tzinfo=None)
def upgrade():
op.add_column('users', sa.Column('created', sa.DateTime, nullable=True))
c = op.get_bind()
# fill created date with current time
now = datetime.utcnow()
now = utcnow()
c.execute(
"""
UPDATE users

View File

@@ -2,7 +2,6 @@
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
import json
from datetime import datetime
from unittest import mock
from urllib.parse import parse_qsl, quote, urlencode, urlparse, urlunparse
@@ -10,7 +9,7 @@ from oauthlib import oauth2
from tornado import web
from .. import orm, roles, scopes
from ..utils import get_browser_protocol, token_authenticated
from ..utils import get_browser_protocol, token_authenticated, utcnow
from .base import APIHandler, BaseHandler
@@ -39,7 +38,7 @@ class TokenAPIHandler(APIHandler):
self.parsed_scopes = scopes.parse_scopes(self.expanded_scopes)
# record activity whenever we see a token
now = orm_token.last_activity = datetime.utcnow()
now = orm_token.last_activity = utcnow(with_tz=False)
if orm_token.user:
orm_token.user.last_activity = now
model = self.user_model(self.users[orm_token.user])

View File

@@ -4,7 +4,7 @@
import asyncio
import inspect
import json
from datetime import datetime, timedelta, timezone
from datetime import timedelta, timezone
from async_generator import aclosing
from dateutil.parser import parse as parse_date
@@ -23,6 +23,7 @@ from ..utils import (
maybe_future,
url_escape_path,
url_path_join,
utcnow,
)
from .base import APIHandler
@@ -367,7 +368,7 @@ class UserTokenListAPIHandler(APIHandler):
if not user:
raise web.HTTPError(404, "No such user: %s" % user_name)
now = datetime.utcnow()
now = utcnow(with_tz=False)
api_tokens = []
def sort_key(token):
@@ -843,7 +844,7 @@ def _parse_timestamp(timestamp):
# strip timezone info to naive UTC datetime
dt = dt.astimezone(timezone.utc).replace(tzinfo=None)
now = datetime.utcnow()
now = utcnow(with_tz=False)
if (dt - now) > timedelta(minutes=59):
raise web.HTTPError(
400,

View File

@@ -96,6 +96,7 @@ from .utils import (
subdomain_hook_idna,
subdomain_hook_legacy,
url_path_join,
utcnow,
)
common_aliases = {
@@ -2093,7 +2094,7 @@ class JupyterHub(Application):
# we don't want to allow user.created to be undefined,
# so initialize it to last_activity (if defined) or now.
if not user.created:
user.created = user.last_activity or datetime.utcnow()
user.created = user.last_activity or utcnow(with_tz=False)
db.commit()
# The allowed_users set and the users in the db are now the same.
@@ -3273,7 +3274,7 @@ class JupyterHub(Application):
routes = await self.proxy.get_all_routes()
users_count = 0
active_users_count = 0
now = datetime.utcnow()
now = utcnow(with_tz=False)
for prefix, route in routes.items():
route_data = route['data']
if 'user' not in route_data:

View File

@@ -10,7 +10,7 @@ import re
import time
import uuid
import warnings
from datetime import datetime, timedelta
from datetime import timedelta
from http.client import responses
from urllib.parse import parse_qs, parse_qsl, urlencode, urlparse, urlunparse
@@ -47,6 +47,7 @@ from ..utils import (
maybe_future,
url_escape_path,
url_path_join,
utcnow,
)
# pattern for the authentication token header
@@ -293,7 +294,7 @@ class BaseHandler(RequestHandler):
recorded (bool): True if activity was recorded, False if not.
"""
if timestamp is None:
timestamp = datetime.utcnow()
timestamp = utcnow(with_tz=False)
resolution = self.settings.get("activity_resolution", 0)
if not obj.last_activity or resolution == 0:
self.log.debug("Recording first activity for %s", obj)
@@ -381,7 +382,7 @@ class BaseHandler(RequestHandler):
orm_token = self.get_token()
if orm_token is None:
return None
now = datetime.utcnow()
now = utcnow(with_tz=False)
recorded = self._record_activity(orm_token, now)
if orm_token.user:
# FIXME: scopes should give us better control than this

View File

@@ -14,7 +14,7 @@ from tornado.httputil import url_concat
from .. import __version__
from ..metrics import SERVER_POLL_DURATION_SECONDS, ServerPollStatus
from ..scopes import needs_scope
from ..utils import maybe_future, url_escape_path, url_path_join
from ..utils import maybe_future, url_escape_path, url_path_join, utcnow
from .base import BaseHandler
@@ -484,7 +484,7 @@ class TokenPageHandler(BaseHandler):
def sort_key(token):
return (token.last_activity or never, token.created or never)
now = datetime.utcnow()
now = utcnow(with_tz=False)
# group oauth client tokens by client id
all_tokens = defaultdict(list)

View File

@@ -4,7 +4,8 @@
import enum
import json
from base64 import decodebytes, encodebytes
from datetime import datetime, timedelta
from datetime import timedelta
from functools import partial
import alembic.command
import alembic.config
@@ -40,10 +41,10 @@ from sqlalchemy.pool import StaticPool
from sqlalchemy.types import LargeBinary, Text, TypeDecorator
from tornado.log import app_log
from .utils import compare_token, hash_token, new_token, random_port
from .utils import compare_token, hash_token, new_token, random_port, utcnow
# top-level variable for easier mocking in tests
utcnow = datetime.utcnow
utcnow = partial(utcnow, with_tz=False)
class JSONDict(TypeDecorator):
@@ -278,7 +279,7 @@ class User(Base):
return {s.name: s for s in self._orm_spawners}
admin = Column(Boolean(create_constraint=False), default=False)
created = Column(DateTime, default=datetime.utcnow)
created = Column(DateTime, default=utcnow)
last_activity = Column(DateTime, nullable=True)
api_tokens = relationship(
@@ -665,8 +666,8 @@ class APIToken(Hashed, Base):
session_id = Column(Unicode(255), nullable=True)
# token metadata for bookkeeping
now = datetime.utcnow # for expiry
created = Column(DateTime, default=datetime.utcnow)
now = utcnow # for expiry
created = Column(DateTime, default=utcnow)
expires_at = Column(DateTime, default=None, nullable=True)
last_activity = Column(DateTime)
note = Column(Unicode(1023))
@@ -855,7 +856,7 @@ class OAuthCode(Expiring, Base):
@staticmethod
def now():
return datetime.utcnow().timestamp()
return utcnow(with_tz=True).timestamp()
@classmethod
def find(cls, db, code):

View File

@@ -4,11 +4,11 @@ Run with old versions of jupyterhub to test upgrade/downgrade
used in test_db.py
"""
from datetime import datetime
from functools import partial
import jupyterhub
from jupyterhub import orm
from jupyterhub.utils import utcnow
def populate_db(url):
@@ -117,10 +117,11 @@ def populate_db(url):
assert user.created
assert admin.created
# set last_activity
user.last_activity = datetime.utcnow()
now = utcnow().replace(tzinfo=None)
user.last_activity = now
spawner = user.orm_spawners['']
spawner.started = datetime.utcnow()
spawner.last_activity = datetime.utcnow()
spawner.started = now
spawner.last_activity = now
db.commit()

View File

@@ -2444,7 +2444,7 @@ async def test_update_server_activity(app, user, server_name, fresh):
# we use naive utc internally
# initialize last_activity for one named and the default server
for name in ("", "exists"):
user.spawners[name].orm_spawner.last_activity = now.replace(tzinfo=None)
user.spawners[name].orm_spawner.last_activity = internal_now
app.db.commit()
td = timedelta(minutes=1)

View File

@@ -3,7 +3,7 @@
# Distributed under the terms of the Modified BSD License.
import os
import socket
from datetime import datetime, timedelta
from datetime import timedelta
from unittest import mock
import pytest
@@ -11,6 +11,7 @@ import pytest
from .. import crypto, objects, orm, roles
from ..emptyclass import EmptyClass
from ..user import User
from ..utils import utcnow
from .mocking import MockSpawner
@@ -121,7 +122,7 @@ def test_token_expiry(db):
user = orm.User(name='parker')
db.add(user)
db.commit()
now = datetime.utcnow()
now = utcnow(with_tz=False)
token = user.new_api_token(expires_in=60)
orm_token = orm.APIToken.find(db, token=token)
assert orm_token
@@ -506,7 +507,7 @@ def test_expiring_api_token(app, user):
assert found is orm_token
with mock.patch.object(
orm.APIToken, 'now', lambda: datetime.utcnow() + timedelta(seconds=60)
orm.APIToken, 'now', lambda: utcnow(with_tz=False) + timedelta(seconds=60)
):
found = orm.APIToken.find(db, token)
assert found is None

View File

@@ -3,7 +3,7 @@
import json
import warnings
from collections import defaultdict
from datetime import datetime, timedelta
from datetime import timedelta
from urllib.parse import quote, urlparse
from sqlalchemy import inspect
@@ -25,6 +25,7 @@ from .utils import (
subdomain_hook_legacy,
url_escape_path,
url_path_join,
utcnow,
)
# detailed messages about the most common failure-to-start errors,
@@ -757,7 +758,7 @@ class User:
# update spawner start time, and activity for both spawner and user
self.last_activity = (
spawner.orm_spawner.started
) = spawner.orm_spawner.last_activity = datetime.utcnow()
) = spawner.orm_spawner.last_activity = utcnow(with_tz=False)
db.commit()
# wait for spawner.start to return
# run optional preparation work to bootstrap the notebook
@@ -964,7 +965,9 @@ class User:
status = await spawner.poll()
if status is None:
await spawner.stop()
self.last_activity = spawner.orm_spawner.last_activity = datetime.utcnow()
self.last_activity = spawner.orm_spawner.last_activity = utcnow(
with_tz=False
)
# remove server entry from db
spawner.server = None
if not spawner.will_resume:

View File

@@ -654,9 +654,18 @@ async def iterate_until(deadline_future, generator):
continue
def utcnow():
"""Return timezone-aware utcnow"""
return datetime.now(timezone.utc)
def utcnow(*, with_tz=True):
"""Return utcnow
with_tz (default): returns tz-aware datetime in UTC
if with_tz=False, returns UTC timestamp without tzinfo
(used for most internal timestamp storage because databases often don't preserve tz info)
"""
now = datetime.now(timezone.utc)
if not with_tz:
now = now.replace(tzinfo=None)
return now
def _parse_accept_header(accept):