| rjw | 2e8229f | 2022-02-15 21:08:12 +0800 | [diff] [blame] | 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 |  | 
|  | 10 | from __future__ import absolute_import | 
|  | 11 |  | 
|  | 12 | import sys | 
|  | 13 | import importlib | 
|  | 14 |  | 
|  | 15 | from serial.serialutil import * | 
|  | 16 | #~ SerialBase, SerialException, to_bytes, iterbytes | 
|  | 17 |  | 
|  | 18 | __version__ = '3.5' | 
|  | 19 |  | 
|  | 20 | VERSION = __version__ | 
|  | 21 |  | 
|  | 22 | # pylint: disable=wrong-import-position | 
|  | 23 | if sys.platform == 'cli': | 
|  | 24 | from serial.serialcli import Serial | 
|  | 25 | else: | 
|  | 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 |  | 
|  | 38 | protocol_handler_packages = [ | 
|  | 39 | 'serial.urlhandler', | 
|  | 40 | ] | 
|  | 41 |  | 
|  | 42 |  | 
|  | 43 | def 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 |