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