__init__.py 3.1 KB

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