blob: caa4de1f5805d4a9673967a83e96e19fbf078c31 [file] [log] [blame]
rjw2e8229f2022-02-15 21:08:12 +08001#!/usr/bin/env python
2#
3# This is a wrapper module for different platform implementations
4#
5# This file is part of pySerial. https://github.com/pyserial/pyserial
6# (C) 2001-2020 Chris Liechti <cliechti@gmx.net>
7#
8# SPDX-License-Identifier: BSD-3-Clause
9
10from __future__ import absolute_import
11
12import sys
13import importlib
14
15from serial.serialutil import *
16#~ SerialBase, SerialException, to_bytes, iterbytes
17
18__version__ = '3.5'
19
20VERSION = __version__
21
22# pylint: disable=wrong-import-position
23if sys.platform == 'cli':
24 from serial.serialcli import Serial
25else:
26 import os
27 # chose an implementation, depending on os
28 if os.name == 'nt': # sys.platform == 'win32':
29 from serial.serialwin32 import Serial
30 elif os.name == 'posix':
31 from serial.serialposix import Serial, PosixPollSerial, VTIMESerial # noqa
32 elif os.name == 'java':
33 from serial.serialjava import Serial
34 else:
35 raise ImportError("Sorry: no implementation for your platform ('{}') available".format(os.name))
36
37
38protocol_handler_packages = [
39 'serial.urlhandler',
40]
41
42
43def serial_for_url(url, *args, **kwargs):
44 """\
45 Get an instance of the Serial class, depending on port/url. The port is not
46 opened when the keyword parameter 'do_not_open' is true, by default it
47 is. All other parameters are directly passed to the __init__ method when
48 the port is instantiated.
49
50 The list of package names that is searched for protocol handlers is kept in
51 ``protocol_handler_packages``.
52
53 e.g. we want to support a URL ``foobar://``. A module
54 ``my_handlers.protocol_foobar`` is provided by the user. Then
55 ``protocol_handler_packages.append("my_handlers")`` would extend the search
56 path so that ``serial_for_url("foobar://"))`` would work.
57 """
58 # check and remove extra parameter to not confuse the Serial class
59 do_open = not kwargs.pop('do_not_open', False)
60 # the default is to use the native implementation
61 klass = Serial
62 try:
63 url_lowercase = url.lower()
64 except AttributeError:
65 # it's not a string, use default
66 pass
67 else:
68 # if it is an URL, try to import the handler module from the list of possible packages
69 if '://' in url_lowercase:
70 protocol = url_lowercase.split('://', 1)[0]
71 module_name = '.protocol_{}'.format(protocol)
72 for package_name in protocol_handler_packages:
73 try:
74 importlib.import_module(package_name)
75 handler_module = importlib.import_module(module_name, package_name)
76 except ImportError:
77 continue
78 else:
79 if hasattr(handler_module, 'serial_class_for_url'):
80 url, klass = handler_module.serial_class_for_url(url)
81 else:
82 klass = handler_module.Serial
83 break
84 else:
85 raise ValueError('invalid URL, protocol {!r} not known'.format(protocol))
86 # instantiate and open when desired
87 instance = klass(None, *args, **kwargs)
88 instance.port = url
89 if do_open:
90 instance.open()
91 return instance