简体   繁体   English

将 python 队列模块从 python2 转换为 python3

[英]converting the python queue module from python2 to python3

I have a logging script that will log serial output from multiple devices in a queue of serial terms into stdout.我有一个日志记录脚本,它将串行项队列中多个设备的串行输出记录到标准输出中。 In python 2.7 the script worked as intended.在 python 2.7 中,脚本按预期工作。 However upon converting the script to python3.但是,将脚本转换为 python3. I noticed that after I converted the queue module to its python3 form, my script started printing out empty lines in addition to the regular expected output.我注意到,在将队列模块转换为它的 python3 形式后,我的脚本开始打印除了常规预期输出之外的空行。 Could someone explain what the cause of this is and any best practice to fix this?有人可以解释这是什么原因以及解决此问题的任何最佳做法吗?

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-

import serial
import sys
import threading
from datetime import datetime
import glob
import time
import os
import termcolor as tc
import queue

__version__ = 2.0

COLOR = True
# Available colors
#   blue, yellow, green, cyan,
#   magenta, white, red, grey,
#   light_grey, on_red

# Add light grey to the colors dictionary
tc.COLORS['light_grey'] = 38
# Add a highlight color
tc.COLORS['on_red'] = 41

TIMEOUT = 0.05 # seconds

DEVS = []
usb_devices = []
speaker_types = ['Tx', 'Rx-FL', 'Rx-FR', 'Rx-Center', 'Rx-Subwoofer']

stamp = time.strftime("%Y:%m:%d-%H:%M:%S")

def serial_ports():
    if sys.platform.startswith('win'):
        ports = ['COM%s' % (i + 1) for i in range(256)]
    elif sys.platform.startswith('linux') or sys.platform.startswith('cygwin'):
        ports = glob.glob('/dev/tty[A-Za-z]*')
    elif sys.platform.startswith('darwin'):
        ports = glob.glob('/dev/tty.*')
    else:
        raise EnvironmentError('Unsupported platform')
    result = []
    for port in ports:
        try:
            s = serial.Serial(port)
            s.close()
            result.append(port)
        except (OSError, serial.SerialException):
            pass
    result.reverse()
    print("Ports: " + str(result))
    pattern = 'USB'
    usb_devices = [string for string in result if pattern in string]
    return usb_devices
    
def add_device(position):    
    name = speaker_types[position]
    return name


class SerialTerm(object):
    """A serial terminal that runs in its own thread"""
    def __init__(self, name, port, timeout, queue, baudrate=2000000, color=None):
        self.name = name
        self.port = port
        self.timeout = timeout
        self.queue = queue
        self.baudrate = baudrate
        self.color = color

        self.receiver_thread = None
        self.alive = None

        self.serial = serial.serial_for_url(
            self.port,
            timeout=self.timeout,
            baudrate=self.baudrate)

    def start(self):
        """Starts the terminal thread"""
        self.alive = True
        self.receiver_thread = threading.Thread(target=self.reader)
        self.receiver_thread.setDaemon(True)
        self.receiver_thread.start()
        #self.reset()

    def stop(self):
        """Stops the terminal thread"""
        self.alive = False
        self.receiver_thread.join()

    def reader(self):
        """Reads data from the associated serial port and puts the data in a
        queue"""
        while self.alive:
            now = datetime.utcnow()
            line = self.serial.readline()
            if line != "": 
                output_str = f"{now.time().isoformat()[:12]}(UTC) {self.name}> {line}"

                if COLOR and (self.color is not None):
                    output_str = tc.colored(output_str, self.color)
                    
                self.queue.put(output_str)


    def join(self):
        """Waits until thread terminates"""
        self.receiver_thread.join()
        
def main():
    print("Getting Devices")
    dev = serial_ports()
    
    position = 0
    name = ''

    for d in dev:
        name = add_device(position)
        DEVS.append({'port':dev[position], 'name':name, 'color':'white'})
        position += 1
        
    print('DEVS: ' + str(DEVS))
    
    """Round robin serial polling"""
    sys.stdout.write("v{}\n".format(__version__))
    sys.stdout.flush()
    que = queue.Queue()

    terms = []
    for dev in DEVS:
        terms.append(
            SerialTerm(
                name=dev['name'],
                port=dev['port'],
                color=dev['color'],
                timeout=TIMEOUT,
                queue=que))

    for term in terms:
        term.start()

    try:
        while True:
            try:
                # The queue.get method needs a timeout or KeyboardInterrupt won't ever raise.
                sys.stdout.write(que.get(timeout=60) + "\n")
                sys.stdout.flush()
            except queue.Empty: 
                pass
    except KeyboardInterrupt:
        sys.stderr.write("\nQuitting\n")
        for term in terms:
           term.stop()
           term.join()
           sys.exit()
           sys.stdout.flush()
    except:
        raise

if __name__ == '__main__':
    main()

Here is an example of the bad output python3 has been giving me.这是 python3 给我的错误输出示例。 It would just spam these empty lines indefinitely in addition to any normal printout that is displayed.除了显示的任何正常打印输出之外,它只会无限期地向这些空行发送垃圾邮件。

00:53:00.859(UTC) Tx> b''
00:53:00.909(UTC) Tx> b''
00:53:00.960(UTC) Tx> b''
00:53:01.010(UTC) Tx> b''
00:53:01.061(UTC) Tx> b''
00:53:01.111(UTC) Tx> b''
00:53:00.859(UTC) Tx> b'Expected Printout'
00:53:00.909(UTC) Tx> b''
00:53:00.960(UTC) Tx> b''
00:53:01.010(UTC) Tx> b''
00:53:01.061(UTC) Tx> b''
00:53:01.111(UTC) Tx> b''

the bug is here:错误在这里:

            line = self.serial.readline()
            if line != "": 
                output_str = f"{now.time().isoformat()[:12]}(UTC) {self.name}> {line}"

                if COLOR and (self.color is not None):
                    output_str = tc.colored(output_str, self.color)
                    
                self.queue.put(output_str)

self.serial.readline() returns a bytes object. self.serial.readline()返回一个bytes对象。 As a result, it will not compare equal to str objects such as "" , so empty lines are no longer filtered out.结果,它不会比较等于str对象,例如"" ,因此不再过滤掉空行。

To fix it, you will need to convert the return value of self.serial.readline() to str with bytes.decode要修复它,您需要使用bytes.decodeself.serial.readline()的返回值转换为str

See this guide for more details about the changes to strings made in python 3, and how to properly port python 2 code.有关在 python 3 中对字符串所做的更改以及如何正确移植 python 2 代码的更多详细信息, 请参阅本指南

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM