Skip to content

Remove support for old Python versions #594

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
May 19, 2019
6 changes: 1 addition & 5 deletions .appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,10 @@ environment:

# For Python versions available on Appveyor, see
# https://www.appveyor.com/docs/windows-images-software/#python
# Python pre-2.7 and 3.0-3.4 have reached EOL
# Only Python 3.6+ is supported

- PYTHON: "C:\\Python27"
- PYTHON: "C:\\Python35"
- PYTHON: "C:\\Python36"
- PYTHON: "C:\\Python37"
- PYTHON: "C:\\Python27-x64"
- PYTHON: "C:\\Python35-x64"
- PYTHON: "C:\\Python36-x64"
- PYTHON: "C:\\Python37-x64"

Expand Down
5 changes: 1 addition & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,12 @@ cache:
- "$HOME/.cache/pip"

python:
# CPython; versions pre-2.7 and 3.0-3.5 have reached EOL
- "2.7"
# CPython; only 3.6 is supported
- "3.6"
- "3.7"
- 3.8-dev
- nightly
# PyPy:
- pypy # Python 2.7
- pypy3.5 # Python 3.5
- pypy3

env:
Expand Down
4 changes: 2 additions & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,15 @@ Python developers; providing common abstractions to
different hardware devices, and a suite of utilities for sending and receiving
messages on a can bus.

The library supports Python 2.7, Python 3.5+ as well as PyPy 2 & 3 and runs
The library currently supports Python 3.6+ as well as PyPy 3 and runs
on Mac, Linux and Windows.

================== ===========
Library Version Python
------------------ -----------
2.x 2.6+, 3.4+
3.x 2.7+, 3.5+
4.x (expected) 3.6+
4.x 3.6+
================== ===========


Expand Down
8 changes: 1 addition & 7 deletions can/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
``can`` is an object-orient Controller Area Network (CAN) interface module.
"""

from __future__ import absolute_import

import logging

__version__ = "3.2.0"
Expand All @@ -22,11 +20,7 @@ class CanError(IOError):
pass


from .listener import Listener, BufferedReader, RedirectReader
try:
from .listener import AsyncBufferedReader
except ImportError:
pass
from .listener import Listener, BufferedReader, RedirectReader, AsyncBufferedReader

from .io import Logger, Printer, LogReader, MessageSync
from .io import ASCWriter, ASCReader
Expand Down
2 changes: 1 addition & 1 deletion can/broadcastmanager.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
log = logging.getLogger('can.bcm')


class CyclicTask(object):
class CyclicTask:
"""
Abstract Base for all cyclic tasks.
"""
Expand Down
6 changes: 1 addition & 5 deletions can/bus.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
Contains the ABC bus implementation and its documentation.
"""

from __future__ import print_function, absolute_import

from abc import ABCMeta, abstractmethod
import logging
import threading
Expand All @@ -26,7 +24,7 @@ class BusState(Enum):
ERROR = auto()


class BusABC(object):
class BusABC(metaclass=ABCMeta):
"""The CAN Bus Abstract Base Class that serves as the basis
for all concrete interfaces.

Expand Down Expand Up @@ -403,5 +401,3 @@ def _detect_available_configs():
for usage in the interface's bus constructor.
"""
raise NotImplementedError()

__metaclass__ = ABCMeta
13 changes: 3 additions & 10 deletions can/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
CyclicSendTasks.
"""

from __future__ import absolute_import, print_function

import sys
import importlib
import logging
Expand All @@ -18,10 +16,6 @@
from .util import load_config
from .interfaces import BACKENDS

# Required by "detect_available_configs" for argument interpretation
if sys.version_info.major > 2:
basestring = str

log = logging.getLogger('can.interface')
log_autodetect = log.getChild('detect_available_configs')

Expand Down Expand Up @@ -144,10 +138,9 @@ def detect_available_configs(interfaces=None):

# Figure out where to search
if interfaces is None:
# use an iterator over the keys so we do not have to copy it
interfaces = BACKENDS.keys()
elif isinstance(interfaces, basestring):
interfaces = [interfaces, ]
interfaces = BACKENDS
elif isinstance(interfaces, str):
interfaces = (interfaces, )
# else it is supposed to be an iterable of strings

result = []
Expand Down
2 changes: 2 additions & 0 deletions can/interfaces/canalystii.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# coding: utf-8

from ctypes import *
import logging
import platform
Expand Down
2 changes: 0 additions & 2 deletions can/interfaces/iscan.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
Interface for isCAN from Thorsis Technologies GmbH, former ifak system GmbH.
"""

from __future__ import absolute_import, division

import ctypes
import time
import logging
Expand Down
8 changes: 1 addition & 7 deletions can/interfaces/ixxat/canlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@

"""

from __future__ import absolute_import, division

import ctypes
import functools
import logging
Expand All @@ -32,11 +30,7 @@

log = logging.getLogger('can.ixxat')

try:
# since Python 3.3
from time import perf_counter as _timer_function
except ImportError:
from time import clock as _timer_function
from time import perf_counter as _timer_function

# Hack to have vciFormatError as a free function, see below
vciFormatError = None
Expand Down
2 changes: 0 additions & 2 deletions can/interfaces/kvaser/canlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
Copyright (C) 2010 Dynamic Controls
"""

from __future__ import absolute_import

import sys
import time
import logging
Expand Down
15 changes: 3 additions & 12 deletions can/interfaces/pcan/pcan.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
Enable basic CAN over a PCAN USB device.
"""

from __future__ import absolute_import, print_function, division

import logging
import sys
import time
Expand All @@ -16,8 +14,8 @@
from can.util import len2dlc, dlc2len
from .basic import *

boottimeEpoch = 0
try:
# use the "uptime" library if available
import uptime
import datetime
boottimeEpoch = (uptime.boottime() - datetime.datetime.utcfromtimestamp(0)).total_seconds()
Expand All @@ -39,13 +37,6 @@
# Use polling instead
HAS_EVENTS = False

try:
# new in 3.3
timeout_clock = time.perf_counter
except AttributeError:
# deprecated in 3.3
timeout_clock = time.clock

# Set up logging
log = logging.getLogger('can.pcan')

Expand Down Expand Up @@ -277,7 +268,7 @@ def _recv_internal(self, timeout):
timeout_ms = int(timeout * 1000) if timeout is not None else INFINITE
elif timeout is not None:
# Calculate max time
end_time = timeout_clock() + timeout
end_time = time.perf_counter() + timeout

#log.debug("Trying to read a msg")

Expand All @@ -293,7 +284,7 @@ def _recv_internal(self, timeout):
val = WaitForSingleObject(self._recv_event, timeout_ms)
if val != WAIT_OBJECT_0:
return None, False
elif timeout is not None and timeout_clock() >= end_time:
elif timeout is not None and time.perf_counter() >= end_time:
return None, False
else:
result = None
Expand Down
2 changes: 0 additions & 2 deletions can/interfaces/serial/serial_can.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
recording CAN traces.
"""

from __future__ import absolute_import, division

import logging
import struct

Expand Down
2 changes: 0 additions & 2 deletions can/interfaces/slcan.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@

"""

from __future__ import absolute_import

import time
import logging

Expand Down
2 changes: 1 addition & 1 deletion can/interfaces/socketcan/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@
See: https://www.kernel.org/doc/Documentation/networking/can.txt
"""

from can.interfaces.socketcan.socketcan import SocketcanBus, CyclicSendTask, MultiRateCyclicSendTask
from .socketcan import SocketcanBus, CyclicSendTask, MultiRateCyclicSendTask
77 changes: 6 additions & 71 deletions can/interfaces/socketcan/socketcan.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,42 +29,6 @@
pack_filters, find_available_interfaces, error_code_to_str


try:
socket.CAN_BCM
except AttributeError:
HAS_NATIVE_SUPPORT = False
else:
HAS_NATIVE_SUPPORT = True


if not HAS_NATIVE_SUPPORT:
def check_status(result, function, arguments):
if result < 0:
raise can.CanError(error_code_to_str(ctypes.get_errno()))
return result

try:
libc = ctypes.CDLL(ctypes.util.find_library("c"), use_errno=True)
libc.bind.errcheck = check_status
libc.connect.errcheck = check_status
libc.sendto.errcheck = check_status
libc.recvfrom.errcheck = check_status
except:
log.warning("libc is unavailable")
libc = None

def get_addr(sock, channel):
"""Get sockaddr for a channel."""
if channel:
data = struct.pack("16si", channel.encode(), 0)
res = fcntl.ioctl(sock, SIOCGIFINDEX, data)
idx, = struct.unpack("16xi", res)
else:
# All channels
idx = 0
return struct.pack("HiLL", AF_CAN, idx, 0, 0)


# Setup BCM struct
def bcm_header_factory(fields, alignment=8):
curr_stride = 0
Expand Down Expand Up @@ -262,11 +226,7 @@ def dissect_can_frame(frame):
def create_bcm_socket(channel):
"""create a broadcast manager socket and connect to the given interface"""
s = socket.socket(PF_CAN, socket.SOCK_DGRAM, CAN_BCM)
if HAS_NATIVE_SUPPORT:
s.connect((channel,))
else:
addr = get_addr(s, channel)
libc.connect(s.fileno(), addr, len(addr))
s.connect((channel,))
return s


Expand Down Expand Up @@ -421,12 +381,7 @@ def bind_socket(sock, channel='can0'):
If the specified interface isn't found.
"""
log.debug('Binding socket to channel=%s', channel)
if HAS_NATIVE_SUPPORT:
sock.bind((channel,))
else:
# For Python 2.7
addr = get_addr(sock, channel)
libc.bind(sock.fileno(), addr, len(addr))
sock.bind((channel,))
log.debug('Bound socket.')


Expand All @@ -444,22 +399,8 @@ def capture_message(sock, get_channel=False):
# Fetching the Arb ID, DLC and Data
try:
if get_channel:
if HAS_NATIVE_SUPPORT:
cf, addr = sock.recvfrom(CANFD_MTU)
channel = addr[0] if isinstance(addr, tuple) else addr
else:
data = ctypes.create_string_buffer(CANFD_MTU)
addr = ctypes.create_string_buffer(32)
addrlen = ctypes.c_int(len(addr))
received = libc.recvfrom(sock.fileno(), data, len(data), 0,
addr, ctypes.byref(addrlen))
cf = data.raw[:received]
# Figure out the channel name
family, ifindex = struct.unpack_from("Hi", addr.raw)
assert family == AF_CAN
data = struct.pack("16xi", ifindex)
res = fcntl.ioctl(sock, SIOCGIFNAME, data)
channel = ctypes.create_string_buffer(res).value.decode()
cf, addr = sock.recvfrom(CANFD_MTU)
channel = addr[0] if isinstance(addr, tuple) else addr
else:
cf = sock.recv(CANFD_MTU)
channel = None
Expand Down Expand Up @@ -634,13 +575,7 @@ def _send_once(self, data, channel=None):
try:
if self.channel == "" and channel:
# Message must be addressed to a specific channel
if HAS_NATIVE_SUPPORT:
sent = self.socket.sendto(data, (channel, ))
else:
addr = get_addr(self.socket, channel)
sent = libc.sendto(self.socket.fileno(),
data, len(data), 0,
addr, len(addr))
sent = self.socket.sendto(data, (channel, ))
else:
sent = self.socket.send(data)
except socket.error as exc:
Expand Down Expand Up @@ -722,7 +657,7 @@ def receiver(event):
bind_socket(receiver_socket, 'vcan0')
print("Receiver is waiting for a message...")
event.set()
print("Receiver got: ", capture_message(receiver_socket))
print(f"Receiver got: {capture_message(receiver_socket)}")

def sender(event):
event.wait()
Expand Down
1 change: 1 addition & 0 deletions can/interfaces/socketcan/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ def find_available_interfaces():
log.debug("find_available_interfaces(): detected: %s", interface_names)
return filter(_PATTERN_CAN_INTERFACE.match, interface_names)


def error_code_to_str(code):
"""
Converts a given error code (errno) to a useful and human readable string.
Expand Down
1 change: 1 addition & 0 deletions can/interfaces/systec/ucanbus.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class Ucan(UcanServer):
"""
Wrapper around UcanServer to read messages with timeout using events.
"""

def __init__(self):
super(Ucan, self).__init__()
self._msg_received_event = Event()
Expand Down
Loading