require python>=3.5.2

This commit is contained in:
Unrud 2018-08-16 08:00:02 +02:00
parent 59d10ef9f7
commit a5fa35e785
4 changed files with 23 additions and 59 deletions

View File

@ -3,10 +3,6 @@ sudo: false
matrix:
include:
- os: linux
python: 3.3
- os: linux
python: 3.4
- os: linux
python: 3.5
- os: linux

View File

@ -73,10 +73,6 @@ class HTTPServer(wsgiref.simple_server.WSGIServer):
self.server_close()
raise
if self.client_timeout and sys.version_info < (3, 5, 2):
logger.warning("Using server.timeout with Python < 3.5.2 "
"can cause network connection failures")
def get_request(self):
# Set timeout for client
_socket, address = super().get_request()
@ -249,12 +245,8 @@ def serve(configuration):
if configuration.getboolean("server", "ssl") else "")
# Create a socket pair to notify the select syscall of program shutdown
# This is not available in python < 3.5 on Windows
if hasattr(socket, "socketpair"):
shutdown_program_socket_in, shutdown_program_socket_out = (
socket.socketpair())
else:
shutdown_program_socket_in, shutdown_program_socket_out = None, None
shutdown_program_socket_in, shutdown_program_socket_out = (
socket.socketpair())
# SIGTERM and SIGINT (aka KeyboardInterrupt) should just mark this for
# shutdown
@ -265,18 +257,16 @@ def serve(configuration):
return
logger.info("Stopping Radicale")
shutdown_program = True
if shutdown_program_socket_in:
shutdown_program_socket_in.sendall(b"goodbye")
shutdown_program_socket_in.sendall(b" ")
signal.signal(signal.SIGTERM, shutdown)
signal.signal(signal.SIGINT, shutdown)
# Main loop: wait for requests on any of the servers or program shutdown
sockets = list(servers.keys())
if shutdown_program_socket_out:
# Use socket pair to get notified of program shutdown
sockets.append(shutdown_program_socket_out)
# Use socket pair to get notified of program shutdown
sockets.append(shutdown_program_socket_out)
select_timeout = None
if not shutdown_program_socket_out or os.name == "nt":
if os.name == "nt":
# Fallback to busy waiting. (select.select blocks SIGINT on Windows.)
select_timeout = 1.0
logger.info("Radicale server ready")

View File

@ -34,7 +34,6 @@ import pickle
import posixpath
import shlex
import subprocess
import sys
import threading
import time
from contextlib import contextmanager
@ -47,12 +46,9 @@ from tempfile import NamedTemporaryFile, TemporaryDirectory
import vobject
from radicale import xmlutils
from radicale.log import logger
if sys.version_info >= (3, 5):
# HACK: Avoid import cycle for Python < 3.5
from radicale import xmlutils
if os.name == "nt":
import ctypes
import ctypes.wintypes
@ -97,10 +93,6 @@ INTERNAL_TYPES = ("multifilesystem",)
def load(configuration):
"""Load the storage manager chosen in configuration."""
if sys.version_info < (3, 5):
# HACK: Avoid import cycle for Python < 3.5
global xmlutils
from radicale import xmlutils
storage_type = configuration.get("storage", "type")
if storage_type == "multifilesystem":
collection_class = Collection
@ -241,27 +233,6 @@ def find_available_name(exists_fn, suffix=""):
raise RuntimeError("No unique random sequence found")
def scandir(path, only_dirs=False, only_files=False):
"""Iterator for directory elements. (For compatibility with Python < 3.5)
``only_dirs`` only return directories
``only_files`` only return files
"""
if sys.version_info >= (3, 5):
for entry in os.scandir(path):
if ((not only_files or entry.is_file()) and
(not only_dirs or entry.is_dir())):
yield entry.name
else:
for name in os.listdir(path):
p = os.path.join(path, name)
if ((not only_files or os.path.isfile(p)) and
(not only_dirs or os.path.isdir(p))):
yield name
def get_etag(text):
"""Etag from collection or item.
@ -354,7 +325,8 @@ def path_to_filesystem(root, *paths):
# Check for conflicting files (e.g. case-insensitive file systems
# or short names on Windows file systems)
if (os.path.lexists(safe_path) and
part not in scandir(safe_path_parent)):
part not in (e.name for e in
os.scandir(safe_path_parent))):
raise CollidingPathError(part)
return safe_path
@ -899,7 +871,10 @@ class Collection(BaseCollection):
with child_context_manager(sane_path, href):
yield collection.get(href)
for href in scandir(filesystem_path, only_dirs=True):
for entry in os.scandir(filesystem_path):
if not entry.is_dir():
continue
href = entry.name
if not is_safe_filesystem_path_component(href):
if not href.startswith(".Radicale"):
logger.debug("Skipping collection %r in %r",
@ -1174,7 +1149,8 @@ class Collection(BaseCollection):
history_folder = os.path.join(self._filesystem_path,
".Radicale.cache", "history")
try:
for href in scandir(history_folder):
for entry in os.scandir(history_folder):
href = entry.name
if not is_safe_filesystem_path_component(href):
continue
if os.path.isfile(os.path.join(self._filesystem_path, href)):
@ -1285,7 +1261,10 @@ class Collection(BaseCollection):
return token, changes
def list(self):
for href in scandir(self._filesystem_path, only_files=True):
for entry in os.scandir(self._filesystem_path):
if not entry.is_file():
continue
href = entry.name
if not is_safe_filesystem_path_component(href):
if not href.startswith(".Radicale"):
logger.debug("Skipping item %r in %r", href, self.path)
@ -1357,8 +1336,8 @@ class Collection(BaseCollection):
cache_folder = os.path.join(self._filesystem_path, ".Radicale.cache",
"item")
self._clean_cache(cache_folder, (
href for href in scandir(cache_folder) if not
os.path.isfile(os.path.join(self._filesystem_path, href))))
e.name for e in os.scandir(cache_folder) if not
os.path.isfile(os.path.join(self._filesystem_path, e.name))))
def _get_with_metadata(self, href, verify_href=True):
"""Like ``get`` but additonally returns the following metadata:

View File

@ -74,7 +74,7 @@ setup(
"md5": "passlib",
"bcrypt": "passlib[bcrypt]"},
keywords=["calendar", "addressbook", "CalDAV", "CardDAV"],
python_requires=">=3.3",
python_requires=">=3.5.2",
classifiers=[
"Development Status :: 5 - Production/Stable",
"Environment :: Console",
@ -84,8 +84,7 @@ setup(
"License :: OSI Approved :: GNU General Public License (GPL)",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.3",
"Programming Language :: Python :: 3.4",
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Topic :: Office/Business :: Groupware"])