• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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-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
92