pyserial-asyncio-0.4/0000775000175000017500000000000013065564023014214 5ustar lchlch00000000000000pyserial-asyncio-0.4/setup.py0000664000175000017500000000505212777261430015735 0ustar lchlch00000000000000# setup.py for pySerial-asyncio # # For Python 3.x use the corresponding Python executable, # e.g. "python3 setup.py ..." # # (C) 2015-2016 Chris Liechti # # SPDX-License-Identifier: BSD-3-Clause import io import os import re import sys if sys.version_info < (3, 4): raise RuntimeError("pyserial-asyncio requires at least Python 3.4") from setuptools import setup def read(*names, **kwargs): """Python 2 and Python 3 compatible text file reading. Required for single-sourcing the version string. """ with io.open( os.path.join(os.path.dirname(__file__), *names), encoding=kwargs.get("encoding", "utf8") ) as fp: return fp.read() def find_version(*file_paths): """ Search the file for a version string. file_path contain string path components. Reads the supplied Python module as text without importing it. """ version_file = read(*file_paths) version_match = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]", version_file, re.M) if version_match: return version_match.group(1) raise RuntimeError("Unable to find version string.") version = find_version('serial_asyncio', '__init__.py') setup( name="pyserial-asyncio", description="Python Serial Port Extension - Asynchronous I/O support", version=version, author="pySerial-team", url="https://github.com/pyserial/pyserial-asyncio", packages=['serial_asyncio'], install_requires=[ 'pyserial', ], license="BSD", long_description="""\ Async I/O extension package for the Python Serial Port Extension for OSX, Linux, BSD - Documentation: http://pyserial-asyncio.readthedocs.io - Project Homepage: https://github.com/pyserial/pyserial-asyncio """, classifiers=[ #~ 'Development Status :: 5 - Production/Stable', 'Development Status :: 4 - Beta', 'Intended Audience :: Developers', 'Intended Audience :: End Users/Desktop', 'License :: OSI Approved :: BSD License', 'Natural Language :: English', 'Operating System :: POSIX', 'Operating System :: MacOS :: MacOS X', 'Programming Language :: Python', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', 'Topic :: Communications', 'Topic :: Software Development :: Libraries', 'Topic :: Software Development :: Libraries :: Python Modules', 'Topic :: Terminals :: Serial', ], platforms='any', ) pyserial-asyncio-0.4/test/0000775000175000017500000000000013065564023015173 5ustar lchlch00000000000000pyserial-asyncio-0.4/test/__init__.py0000664000175000017500000000000112777254547017313 0ustar lchlch00000000000000 pyserial-asyncio-0.4/test/test_asyncio.py0000664000175000017500000000557413065546503020267 0ustar lchlch00000000000000#!/usr/bin/env python # # This file is part of pySerial-asyncio - Cross platform serial port support for Python # (C) 2016 pySerial-team # # SPDX-License-Identifier: BSD-3-Clause """\ Test asyncio related functionality. To run from the command line with a specific port with a loop-back, device connected, use: $ cd pyserial-asyncio $ python -m test.test_asyncio SERIALDEVICE """ import os import unittest import asyncio import serial_asyncio HOST = '127.0.0.1' _PORT = 8888 # on which port should the tests be performed: PORT = 'socket://%s:%s' % (HOST, _PORT) @unittest.skipIf(os.name != 'posix', "asyncio not supported on platform") class Test_asyncio(unittest.TestCase): """Test asyncio related functionality""" def setUp(self): self.loop = asyncio.get_event_loop() # create a closed serial port def tearDown(self): self.loop.close() def test_asyncio(self): TEXT = b'Hello, World!\n' received = [] actions = [] class Input(asyncio.Protocol): def __init__(self): super().__init__() self._transport = None def connection_made(self, transport): self._transport = transport def data_received(self, data): self._transport.write(data) class Output(asyncio.Protocol): def __init__(self): super().__init__() self._transport = None def connection_made(self, transport): self._transport = transport actions.append('open') transport.write(TEXT) def data_received(self, data): received.append(data) if b'\n' in data: self._transport.close() def connection_lost(self, exc): actions.append('close') self._transport.loop.stop() def pause_writing(self): actions.append('pause') print(self._transport.get_write_buffer_size()) def resume_writing(self): actions.append('resume') print(self._transport.get_write_buffer_size()) if PORT.startswith('socket://'): coro = self.loop.create_server(Input, HOST, _PORT) self.loop.run_until_complete(coro) client = serial_asyncio.create_serial_connection(self.loop, Output, PORT) self.loop.run_until_complete(client) self.loop.run_forever() self.assertEqual(b''.join(received), TEXT) self.assertEqual(actions, ['open', 'close']) if __name__ == '__main__': import sys sys.stdout.write(__doc__) if len(sys.argv) > 1: PORT = sys.argv[1] sys.stdout.write("Testing port: %r\n" % PORT) sys.argv[1:] = ['-v'] # When this module is executed from the command-line, it runs all its tests unittest.main() pyserial-asyncio-0.4/PKG-INFO0000664000175000017500000000227713065564023015321 0ustar lchlch00000000000000Metadata-Version: 1.1 Name: pyserial-asyncio Version: 0.4 Summary: Python Serial Port Extension - Asynchronous I/O support Home-page: https://github.com/pyserial/pyserial-asyncio Author: pySerial-team Author-email: UNKNOWN License: BSD Description: Async I/O extension package for the Python Serial Port Extension for OSX, Linux, BSD - Documentation: http://pyserial-asyncio.readthedocs.io - Project Homepage: https://github.com/pyserial/pyserial-asyncio Platform: any Classifier: Development Status :: 4 - Beta Classifier: Intended Audience :: Developers Classifier: Intended Audience :: End Users/Desktop Classifier: License :: OSI Approved :: BSD License Classifier: Natural Language :: English Classifier: Operating System :: POSIX Classifier: Operating System :: MacOS :: MacOS X Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Topic :: Communications Classifier: Topic :: Software Development :: Libraries Classifier: Topic :: Software Development :: Libraries :: Python Modules Classifier: Topic :: Terminals :: Serial pyserial-asyncio-0.4/LICENSE.txt0000664000175000017500000000353413065563673016056 0ustar lchlch00000000000000Copyright (c) 2015-2017 pySerial-team (see CREDITS.rst) All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------- Note: Individual files contain the following tag instead of the full license text. SPDX-License-Identifier: BSD-3-Clause This enables machine processing of license information based on the SPDX License Identifiers that are here available: http://spdx.org/licenses/ pyserial-asyncio-0.4/documentation/0000775000175000017500000000000013065564023017065 5ustar lchlch00000000000000pyserial-asyncio-0.4/documentation/conf.py0000664000175000017500000001466713024602610020370 0ustar lchlch00000000000000# -*- coding: utf-8 -*- # # pySerial-asyncio documentation build configuration file, created by # sphinx-quickstart on Tue Jul 21 00:27:45 2009. # # This file is execfile()d with the current directory set to its containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys, os # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. #sys.path.append(os.path.abspath('.')) # -- General configuration ----------------------------------------------------- # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = ['sphinx.ext.intersphinx'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8' # The master toctree document. master_doc = 'index' # General information about the project. project = u'pySerial-asyncio' copyright = u'2015-2016, pySerial-team' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = '0.3' # The full version, including alpha/beta/rc tags. release = '0.3' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of documents that shouldn't be included in the build. #unused_docs = [] # List of directories, relative to source directory, that shouldn't be searched # for source files. exclude_trees = ['_build'] # The reST default role (used for this markup: `text`) to use for all documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. Major themes that come with # Sphinx are currently 'default' and 'sphinxdoc'. #html_theme = 'default' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. html_logo = 'pyserial-asyncio.png' # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_use_modindex = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = '' # Output file base name for HTML help builder. #htmlhelp_basename = 'pySerial-asyncio-doc' # -- Options for LaTeX output -------------------------------------------------- # The paper size ('letter' or 'a4'). #latex_paper_size = 'letter' # The font size ('10pt', '11pt' or '12pt'). #latex_font_size = '10pt' # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ ('index', 'pySerial-asyncio.tex', u'pySerial-asyncio Documentation', u'pySerial-team', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. latex_logo = 'pyserial-asyncio.png' # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # Additional stuff for the LaTeX preamble. #latex_preamble = '' # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_use_modindex = True # for external links to standard library intersphinx_mapping = { #~ 'python': ('http://docs.python.org', None), 'py': ('http://docs.python.org', None), } pyserial-asyncio-0.4/documentation/api.rst0000664000175000017500000000277112730371502020373 0ustar lchlch00000000000000====================== pySerial-asyncio API ====================== asyncio ======= .. module:: serial.aio .. warning:: This implementation is currently in an experimental state. Use at your own risk. Experimental asyncio support is available for Python 3.4 and newer. The module :mod:`serial.aio` provides a :class:`asyncio.Transport`: ``SerialTransport``. A factory function (`asyncio.coroutine`) is provided: .. function:: create_serial_connection(loop, protocol_factory, \*args, \*\*kwargs) :param loop: The event handler :param protocol_factory: Factory function for a :class:`asyncio.Protocol` :param args: Passed to the :class:`serial.Serial` init function :param kwargs: Passed to the :class:`serial.Serial` init function :platform: Posix Get a connection making coroutine. Example:: class Output(asyncio.Protocol): def connection_made(self, transport): self.transport = transport print('port opened', transport) transport.serial.rts = False transport.write(b'hello world\n') def data_received(self, data): print('data received', repr(data)) self.transport.close() def connection_lost(self, exc): print('port closed') asyncio.get_event_loop().stop() loop = asyncio.get_event_loop() coro = serial.aio.create_serial_connection(loop, Output, '/dev/ttyUSB0', baudrate=115200) loop.run_until_complete(coro) loop.run_forever() loop.close() pyserial-asyncio-0.4/documentation/pyserial-asyncio.png0000664000175000017500000003205012730371502023062 0ustar lchlch00000000000000PNG  IHDRpVObKGD pHYs  tIME!(OB IDATxw|\ՙNIdKfl"Wb0N$PB $B !}I@3IdwS^H6!$J@056Wܭbɖեsǹ3f$0g>#>yyRcP ;9A3>@{"0 N9S\; .jl'&dD. ffpXdC300@ PxLv4{ єCt.6;6ش/^90 nPL@)@@w†\CJ$rír!N9rr!akNE-e}o!7GrȌ0mN)% K89%aN}.Mؾ0->lTp6(^{ }aw[O}t)1&sB3h' SH>$4瘾 M+7P]k8g-FKM2)6Aoܘìo%?]TdScec˖-Ks/JSWpTÒ1N1VV"f1Fi*c[ ' 1Cb&*=2UDw_ P!쫁TGL '7*̘1c9|>?;1,0uׯn@/ʶC4ww7h * 49,q3 od1ʞJy:ayC ۛuV精 ܕu^5|ʐdizgHŎSؾ>WzK)ɬƮho5l г%.f8[>y&3 lņ p6N:Pmf{iD:<~Z?D嵟VXPd)̉v6-}4=HН$Ojτlj1ƩqW8b!9ҩZdz1C7 5, iJQÆ1s9G:k4o7F~aga,mK/fG'&ę1&΋U1IvWsWcFJ BǮoyL.dCcBwɛV@G$"PD1c׻kӦMe$kS_APX_|ˈ;rG3F^`*tey0C\c6pVa&/xmsR:fK7dKxA[__ϯ[Q]W;eOX\4Bh2emOb k/É 8Ev 4|QSlh &Yv 谾)0:P2Vsd7ţjM6INmš#L&K8*+B]P䶐g1{я~9^BK$=@yO+ri\6+i{TUUՕ !Z\px<xmy!._֭[ҥK)tj| ;mLPԸxCvF#dUf8[fI2}] x}]s}¼u(ȮQ)jKƺ5\:;/JUWWo*$caQiLo%Mǎ;.9 w+W-t^nJ (ͷzky^6y$:S\0Eۨd:@E}X}FŸ9n#wygqLڼ}(S[1AUlj}P?)O O’#hzvmS^ӨXk*7s9&Zɳ^ v4{6sJ \ >7`ב0O[o|\|IkO$J*,oS{̩ٝ}|!`٭yN>06,"3H 56>^Yn&%0ͨ=YU <6q|%igHgcSTYb{Ki Z[Ĕ''zBє(/{45&y]Ђ*Mw.N[C4)&&ԕ9,ګ)@{N?J_RaNi.S$ 2;evvaTGU 8GZt: 6|^yzҕJTըm<'ΉF93M~w_oIECaG8oDح1έo81۸dvc*ey+3F`Ǒ0*|Sz9vZB̫T%kկ>Sѥ/ʚ:; -sw|}?-]t,pyM jRp';{׌C{,C:~;fA \Dm NC!BQAUOU@R/b{C7]IgCiRDo/,Q0j'|oua9>_[0}0oJ8FI߽O'Hi|niH I(2TѓHs2p0d^g{K()v \)Zx~##̚h7H4Oj[}c:X4>sحe6D^Rr7y$Q .It>`o[xZhRU;pBJ; *L,q7`8HQtT:Czr8r X-J-qjƃF~$߮!z ]3{?oIWV=l\*]7 J66f|z !x`Д8'A@[c^T3+m^t#q ]7T0! u8AIi5nXǟ[a4_C%^hZr%N 6:Màk `Jv3-[f2q}(\RJ"ѢG,%Kh蓻P@e^u202L0I>я~pwjX-* fݠ:~4*o] %6G4Aaaa3 /\|FjAR`uk5vM74=6[9"h~n?qllj2\'eBFIƱ~YL*7{e`E `aJc=fjp8'AՎ1Yz:ZBl q?JTW/~#'vET<^?b6]vFp\>'G,K"QRJbNiҫr7wͭ-! %x;'A'ʩ@13QNcPӯ< =~$on1ƥZNd> 2)N`HCgڰXR]m-!:\]_`GJ|a\U&kIZ7Q͑ N tIS*m5fiѺ >t`Xʾԁ]UVٰ&N"zTb1s#xG=ժU˧Z657ƉR]+ɷPLSUCA>1?[cweHP21mr(#| ړPϝO*9MÑ6-^g}C0kPI)ebF &8q4]]ݪr"lH9"y{c׮]MrbZ1K49iʓZ5*p+-ko"C>jѮPQ?CE7ě@l@ _}!q%[ˮE.sq#"S9uϹ5NJ,حI`մX:A2#׫!ô6v JAT9:+QuUUf$uev ?@inxepP5;I$KbJii[o>]:b75ݧTg>;Lb=&4!gYn×zY>!X bIDATbncǁN+%qR.},M;zo !Ƥs{^{^wI3k#!Ss|߰OGkMCl}nj,1/[ou*Is1héG`dǩo!>P+ֽUW]b}}sϭp³r$aCѱaH'˯R Bm-B#a[KDQ)e:5rR THK6S|%RbW=퉓,(!UBRU%1ub^[j*:#~ Ảdzuxao@'Kƺ- xUüJ3&KOa98_HH)VxQVKcVbk2VeVw˦eYisaGJYw ts,8ګc{NӂNq DŽy߿e:KO-Aaiti F%ᨤ;BcWEe DwZ`F٘a4q#{,[+VEcW-!К&/3%yCɡ~@yq #˳qc>2;t:pM!Z{#*@J!;Z,bou'BP>TJN>8-$v :NpnO=GChZOy MyW_u׮]a͚5x<VLw 89T b{ Hb4N 3N˒ҸO&#2cwQF I h9ȁ vbҾEJg}2FB!e_W/|\0kײbK-|MCG=ʚ6 K% dg?[zg~Дű I.qlIm /5i;OZTIu%ACgFW^"VQeӸd"N_Mˊ8 #F[n#͋jt"Prwj}AgxHhK7vü{$LKZ7^x';qM2(*ݣw,zX,^Sj~C[!(+Cj1+ܹsR&&q$UupND^ V,Hꅿ [&C(sZH85ơI3Gtr<>2*E.[t64$F|7EM5=!~]T ={?k@UkXFz hH1cnve޼yx$>>KK\w> dlM$˦5v n1WؙWQ]g}tu S[fruP~Us`R z:6i"CU_81. И9 :]wݢ}_kT:hNC_\Iه q <t6UTƮ_gx0j8'1kA#NMjlqZIf9c#@ŤՖٙ5k%bƲgOq- ]uɸ< EV$jnz]oJjB%l%ym;v ò)N\6.6>B$ V QEN}*IZ4ӨHdtWKg_1P8n%OF8s<Ԕ8obU-̦M]v#\_|ɽs]wI.;32{jsH4-u< Z~B v0y<.XSS l`=m^`%@K*5I'w$m/N3'NC0ii6VHNma7R+O9fx+W|⮻vvJdR?&Ktyn{ BRD1/v!ݞ '@0zȼ*щT˨O\'DF6?IT׮7JH4dGK>576ƢEz{AӌuQ3?9[SEVW;dKeߤ"O7.BO`p"2}Uܪ0:.IOI\:P5s(0-=Qެ`{KRH)=<㚦]UTTHEu|!e#48ؑ^//p,7&ظq㯽^g3yU tN6vk /f8XJBP֙M/C{~sGVI^Qw},Kd R a& ^ :¼ǔq6a8aUg[{"W83ASp'*^@ `τ0F$o "ST/ 9qjݚSӞ3_Pw#]~l@; ̘`^2&Z(N!Oŀg\=meD҄2+s'c>ϕU6icSG)CpZ"N'΍C\xx8bEt3Ě)%6Ξ0c#ko;yy1u-1Q^hpwvıkeai f+VMiF}ma66T%N3]BCG}d**z:-) \暳P+HJdg"oP%&\DO"0WSaIĢ+=|;ɭ yY!'9& zl6OV!=4' 0ƙ=KmqmIsu@I6gPn9iTu,g8iQ&nƹS\TԤhCgMSif )JIQiX-m̮rnXvs98>gΜW\TԨ.Еz@Mcvչj'aU%*O1U xppag :ĹqKL1ľ{Q1ϖ!.=X]+riuk,"+ne(ͳP=֒6B>M6h=[X`IM h)Fl!y6f 1uK?1`ve$GU ]Gœ=2OCgvy ,=ϗ+Bu:8ڠ`$$2 4;;;AE$L7XT*$=ßO*)A| U/P1Msa8q!VC>: S{'yg7H#R:;eQbЩln!4wM 䣵lI?|wwwelsW켯Y8q6fL 1OFC8f!-VbLi8ę}Z'3':2U׎E~,-~4k`d@dM!>Z'<'#%='[~oF .gFL%q\QTxͷҜ#TX9Jq=FTռ5^)<{TM8-@SRw*H>y" XL`cQT?ۼyJ"Et_7Fth^q?o6-B7|T/~ux!foc.Fp^! :phD%Fy&vd!*{uvCը#*VoYU:t]ԓN2 lh d)Y2*G܃f$3'YX`qWn2V//Q7 8CNk캞愞Mq|”&~a_c7 ;FMzɩ3* C7'-3O~.b2]1XaxC)k\4M/ʁ y~';RDxt]E;Z)QfgH4O5:dF8V!Tϲ=^4Tdtv0ZO*S[[٥_:u9bGE@Xϫ11 > ؟=dR̻ oGd%Y3P=nڇ~QC񂆊s1?ܛilG# Ea? EBdؚA7Q_jϙ Yz u$`G$^*㭷ykkkigggIwwwI___V}*Fe0:2TbC'v:px 4 58_5Q}r 3pV4cac92PcnfIhBI_΋L33qrrC#Gr'r!qr!Gr'r'NqrD! 10'?>9i ,`1Su9b םL<ޛ9p:-VB݌nti9nª{DYTiϵa N32QUϻ?ў)CUyra0tTj{+).T!qv!8Q+0SǞk>@z sePv8q3%IENDB`pyserial-asyncio-0.4/documentation/index.rst0000664000175000017500000000172412777254547020752 0ustar lchlch00000000000000.. pySerial-asyncio documentation master file Welcome to pySerial-asyncio's documentation =========================================== `Async I/O`_ extension for the `Python Serial Port`_ package for OSX, Linux, BSD It depends on pySerial and is compatible with Python 3.4 and later. .. _`Async I/O`: https://www.python.org/dev/peps/pep-3156/ .. _`Python Serial Port`: https://pypi.python.org/pypi/pyserial Other pages (online) - `project page on GitHub`_ - `Download Page`_ with releases - This page, when viewed online is at https://pyserial-asyncio.readthedocs.io/en/latest/ or http://pythonhosted.org/pyserial-asyncio/ . .. _Python: http://python.org/ .. _`project page on GitHub`: https://github.com/pyserial/pyserial-asyncio/ .. _`Download Page`: http://pypi.python.org/pypi/pyserial-asyncio Contents: .. toctree:: :maxdepth: 2 shortintro api appendix Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` pyserial-asyncio-0.4/documentation/Makefile0000664000175000017500000000566512730371502020535 0ustar lchlch00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d _build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " changes to make an overview of all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: -rm -rf _build/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) _build/html @echo @echo "Build finished. The HTML pages are in _build/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) _build/dirhtml @echo @echo "Build finished. The HTML pages are in _build/dirhtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) _build/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) _build/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) _build/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in _build/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) _build/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in _build/qthelp, like this:" @echo "# qcollectiongenerator _build/qthelp/pySerial.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile _build/qthelp/pySerial.qhc" latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) _build/latex @echo @echo "Build finished; the LaTeX files are in _build/latex." @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \ "run these through (pdf)latex." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) _build/changes @echo @echo "The overview file is in _build/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) _build/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in _build/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) _build/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in _build/doctest/output.txt." pyserial-asyncio-0.4/documentation/appendix.rst0000664000175000017500000000305712777262055021445 0ustar lchlch00000000000000========== Appendix ========== License ======= Copyright (c) 2015-2016 pySerial-team (see CREDITS.rst) All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. pyserial-asyncio-0.4/documentation/shortintro.rst0000664000175000017500000000215013065546503022033 0ustar lchlch00000000000000================== Short introduction ================== Example:: class Output(asyncio.Protocol): def connection_made(self, transport): self.transport = transport print('port opened', transport) transport.serial.rts = False # You can manipulate Serial object via transport transport.write(b'Hello, World!\n') # Write serial data via transport def data_received(self, data): print('data received', repr(data)) if b'\n' in data: self.transport.close() def connection_lost(self, exc): print('port closed') self.transport.loop.stop() def pause_writing(self): print('pause writing') print(self.transport.get_write_buffer_size()) def resume_writing(self): print(self.transport.get_write_buffer_size()) print('resume writing') loop = asyncio.get_event_loop() coro = create_serial_connection(loop, Output, '/dev/ttyUSB0', baudrate=115200) loop.run_until_complete(coro) loop.run_forever() loop.close() pyserial-asyncio-0.4/MANIFEST.in0000664000175000017500000000046712777776235016004 0ustar lchlch00000000000000include CREDITS.rst include LICENSE.txt include README.rst include MANIFEST.in include requirements.txt include setup.cfg include documentation/*.rst include documentation/conf.py include documentation/Makefile include documentation/pyserial-asyncio.png include test/__init__.py include test/test_asyncio.py pyserial-asyncio-0.4/.travis.yml0000664000175000017500000000037513065546503016335 0ustar lchlch00000000000000# (C) 2016 Chris Liechti # SPDX-License-Identifier: BSD-3-Clause language: python python: - 3.4 - 3.5 - 3.6 install: - pip install -r requirements-travis.txt - pip install -e . script: - python test/test_asyncio.py pyserial-asyncio-0.4/setup.cfg0000664000175000017500000000016513065564023016037 0ustar lchlch00000000000000[flake8] max-line-length = 120 ignore = E265, E126, E241 [egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 pyserial-asyncio-0.4/pyserial_asyncio.egg-info/0000775000175000017500000000000013065564023021263 5ustar lchlch00000000000000pyserial-asyncio-0.4/pyserial_asyncio.egg-info/SOURCES.txt0000664000175000017500000000103413065564023023145 0ustar lchlch00000000000000.travis.yml CREDITS.rst LICENSE.txt MANIFEST.in README.rst requirements.txt setup.cfg setup.py documentation/Makefile documentation/api.rst documentation/appendix.rst documentation/conf.py documentation/index.rst documentation/pyserial-asyncio.png documentation/shortintro.rst pyserial_asyncio.egg-info/PKG-INFO pyserial_asyncio.egg-info/SOURCES.txt pyserial_asyncio.egg-info/dependency_links.txt pyserial_asyncio.egg-info/requires.txt pyserial_asyncio.egg-info/top_level.txt serial_asyncio/__init__.py test/__init__.py test/test_asyncio.pypyserial-asyncio-0.4/pyserial_asyncio.egg-info/dependency_links.txt0000664000175000017500000000000113065564023025331 0ustar lchlch00000000000000 pyserial-asyncio-0.4/pyserial_asyncio.egg-info/PKG-INFO0000664000175000017500000000227713065564023022370 0ustar lchlch00000000000000Metadata-Version: 1.1 Name: pyserial-asyncio Version: 0.4 Summary: Python Serial Port Extension - Asynchronous I/O support Home-page: https://github.com/pyserial/pyserial-asyncio Author: pySerial-team Author-email: UNKNOWN License: BSD Description: Async I/O extension package for the Python Serial Port Extension for OSX, Linux, BSD - Documentation: http://pyserial-asyncio.readthedocs.io - Project Homepage: https://github.com/pyserial/pyserial-asyncio Platform: any Classifier: Development Status :: 4 - Beta Classifier: Intended Audience :: Developers Classifier: Intended Audience :: End Users/Desktop Classifier: License :: OSI Approved :: BSD License Classifier: Natural Language :: English Classifier: Operating System :: POSIX Classifier: Operating System :: MacOS :: MacOS X Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Topic :: Communications Classifier: Topic :: Software Development :: Libraries Classifier: Topic :: Software Development :: Libraries :: Python Modules Classifier: Topic :: Terminals :: Serial pyserial-asyncio-0.4/pyserial_asyncio.egg-info/requires.txt0000664000175000017500000000001113065564023023653 0ustar lchlch00000000000000pyserial pyserial-asyncio-0.4/pyserial_asyncio.egg-info/top_level.txt0000664000175000017500000000001713065564023024013 0ustar lchlch00000000000000serial_asyncio pyserial-asyncio-0.4/serial_asyncio/0000775000175000017500000000000013065564023017220 5ustar lchlch00000000000000pyserial-asyncio-0.4/serial_asyncio/__init__.py0000664000175000017500000004071413065563637021351 0ustar lchlch00000000000000#!/usr/bin/env python3 # # Experimental implementation of asyncio support. # # This file is part of pySerial. https://github.com/pyserial/pyserial-asyncio # (C) 2015-2017 pySerial-team # # SPDX-License-Identifier: BSD-3-Clause """\ Support asyncio with serial ports. EXPERIMENTAL Posix platforms only, Python 3.4+ only. Windows event loops can not wait for serial ports with the current implementation. It should be possible to get that working though. """ import asyncio import os import serial try: import termios except ImportError: termios = None __version__ = '0.4' class SerialTransport(asyncio.Transport): """An asyncio transport model of a serial communication channel. A transport class is an abstraction of a communication channel. This allows protocol implementations to be developed against the transport abstraction without needing to know the details of the underlying channel, such as whether it is a pipe, a socket, or indeed a serial port. You generally won’t instantiate a transport yourself; instead, you will call `create_serial_connection` which will create the transport and try to initiate the underlying communication channel, calling you back when it succeeds. """ def __init__(self, loop, protocol, serial_instance): super().__init__() self._loop = loop self._protocol = protocol self._serial = serial_instance self._closing = False self._protocol_paused = False self._max_read_size = 1024 self._write_buffer = [] self._set_write_buffer_limits() self._has_reader = False self._has_writer = False self._poll_wait_time = 0.0005 # XXX how to support url handlers too # Asynchronous I/O requires non-blocking devices self._serial.timeout = 0 self._serial.write_timeout = 0 # These two callbacks will be enqueued in a FIFO queue by asyncio loop.call_soon(protocol.connection_made, self) loop.call_soon(self._ensure_reader) @property def loop(self): """The asyncio event loop used by this SerialTransport.""" return self._loop @property def serial(self): """The underlying Serial instance.""" return self._serial def __repr__(self): return '{self.__class__.__name__}({self.loop}, {self._protocol}, {self.serial})'.format(self=self) def is_closing(self): """Return True if the transport is closing or closed.""" return self._closing def close(self): """Close the transport gracefully. Any buffered data will be written asynchronously. No more data will be received and further writes will be silently ignored. After all buffered data is flushed, the protocol's connection_lost() method will be called with None as its argument. """ if not self._closing: self._close(None) def _read_ready(self): try: data = self._serial.read(self._max_read_size) except serial.SerialException as e: self._close(exc=e) else: if data: self._protocol.data_received(data) def write(self, data): """Write some data to the transport. This method does not block; it buffers the data and arranges for it to be sent out asynchronously. Writes made after the transport has been closed will be ignored.""" if self._closing: return if self.get_write_buffer_size() == 0: # Attempt to send it right away first try: n = self._serial.write(data) except serial.SerialException as exc: self._fatal_error(exc, 'Fatal write error on serial transport') return if n == len(data): return # Whole request satisfied assert 0 <= n < len(data) data = data[n:] self._ensure_writer() self._write_buffer.append(data) self._maybe_pause_protocol() def can_write_eof(self): """Serial ports do not support the concept of end-of-file. Always returns False. """ return False def pause_reading(self): """Pause the receiving end of the transport. No data will be passed to the protocol’s data_received() method until resume_reading() is called. """ self._remove_reader() def resume_reading(self): """Resume the receiving end of the transport. Incoming data will be passed to the protocol's data_received() method until pause_reading() is called. """ self._ensure_reader() def set_write_buffer_limits(self, high=None, low=None): """Set the high- and low-water limits for write flow control. These two values control when the protocol’s pause_writing()and resume_writing() methods are called. If specified, the low-water limit must be less than or equal to the high-water limit. Neither high nor low can be negative. """ self._set_write_buffer_limits(high=high, low=low) self._maybe_pause_protocol() def get_write_buffer_size(self): """The number of bytes in the write buffer. This buffer is unbounded, so the result may be larger than the the high water mark. """ return sum(map(len, self._write_buffer)) def write_eof(self): raise NotImplementedError("Serial connections do not support end-of-file") def abort(self): """Close the transport immediately. Pending operations will not be given opportunity to complete, and buffered data will be lost. No more data will be received and further writes will be ignored. The protocol's connection_lost() method will eventually be called. """ self._abort(None) def _maybe_pause_protocol(self): """To be called whenever the write-buffer size increases. Tests the current write-buffer size against the high water mark configured for this transport. If the high water mark is exceeded, the protocol is instructed to pause_writing(). """ if self.get_write_buffer_size() <= self._high_water: return if not self._protocol_paused: self._protocol_paused = True try: self._protocol.pause_writing() except Exception as exc: self._loop.call_exception_handler({ 'message': 'protocol.pause_writing() failed', 'exception': exc, 'transport': self, 'protocol': self._protocol, }) def _maybe_resume_protocol(self): """To be called whenever the write-buffer size decreases. Tests the current write-buffer size against the low water mark configured for this transport. If the write-buffer size is below the low water mark, the protocol is instructed that is can resume_writing(). """ if (self._protocol_paused and self.get_write_buffer_size() <= self._low_water): self._protocol_paused = False try: self._protocol.resume_writing() except Exception as exc: self._loop.call_exception_handler({ 'message': 'protocol.resume_writing() failed', 'exception': exc, 'transport': self, 'protocol': self._protocol, }) def _write_ready(self): """Asynchronously write buffered data. This method is called back asynchronously as a writer registered with the asyncio event-loop against the underlying file descriptor for the serial port. Should the write-buffer become empty if this method is invoked while the transport is closing, the protocol's connection_lost() method will be called with None as its argument. """ data = b''.join(self._write_buffer) assert data, 'Write buffer should not be empty' self._write_buffer.clear() try: n = self._serial.write(data) except (BlockingIOError, InterruptedError): self._write_buffer.append(data) except serial.SerialException as exc: self._fatal_error(exc, 'Fatal write error on serial transport') else: if n == len(data): assert self._flushed() self._remove_writer() self._maybe_resume_protocol() # May cause further writes # _write_ready may have been invoked by the event loop # after the transport was closed, as part of the ongoing # process of flushing buffered data. If the buffer # is now empty, we can close the connection if self._closing and self._flushed(): self._close() return assert 0 <= n < len(data) data = data[n:] self._write_buffer.append(data) # Try again later self._maybe_resume_protocol() assert self._has_writer if os.name == "nt": def _poll_read(self): if self._has_reader: if self.serial.in_waiting: self._loop.call_soon(self._read_ready) self._loop.call_later(self._poll_wait_time, self._poll_read) def _ensure_reader(self): if (not self._has_reader) and (not self._closing): self._loop.call_later(self._poll_wait_time, self._poll_read) self._has_reader = True def _remove_reader(self): self._has_reader = False def _poll_write(self): if self._has_writer: if self.serial.out_waiting: self._loop.call_soon(self._write_ready) self._loop.call_later(self._poll_wait_time, self._poll_write) def _ensure_writer(self): if (not self._has_writer) and (not self._closing): self._loop.call_later(self._poll_wait_time, self._poll_write) self._has_writer = True def _remove_writer(self): self._has_writer = False else: def _ensure_reader(self): if (not self._has_reader) and (not self._closing): self._loop.add_reader(self._serial.fileno(), self._read_ready) self._has_reader = True def _remove_reader(self): if self._has_reader: self._loop.remove_reader(self._serial.fileno()) self._has_reader = False def _ensure_writer(self): if (not self._has_writer) and (not self._closing): self._loop.add_writer(self._serial.fileno(), self._write_ready) self._has_writer = True def _remove_writer(self): if self._has_writer: self._loop.remove_writer(self._serial.fileno()) self._has_writer = False def _set_write_buffer_limits(self, high=None, low=None): """Ensure consistent write-buffer limits.""" if high is None: high = 64 * 1024 if low is None else 4 * low if low is None: low = high // 4 if not high >= low >= 0: raise ValueError('high (%r) must be >= low (%r) must be >= 0' % (high, low)) self._high_water = high self._low_water = low def _fatal_error(self, exc, message='Fatal error on serial transport'): """Report a fatal error to the event-loop and abort the transport.""" self._loop.call_exception_handler({ 'message': message, 'exception': exc, 'transport': self, 'protocol': self._protocol, }) self._abort(exc) def _flushed(self): """True if the write buffer is empty, otherwise False.""" return self.get_write_buffer_size() == 0 def _close(self, exc=None): """Close the transport gracefully. If the write buffer is already empty, writing will be stopped immediately and a call to the protocol's connection_lost() method scheduled. If the write buffer is not already empty, the asynchronous writing will continue, and the _write_ready method will call this _close method again when the buffer has been flushed completely. """ self._closing = True self._remove_reader() if self._flushed(): self._remove_writer() self._loop.call_soon(self._call_connection_lost, exc) def _abort(self, exc): """Close the transport immediately. Pending operations will not be given opportunity to complete, and buffered data will be lost. No more data will be received and further writes will be ignored. The protocol's connection_lost() method will eventually be called with the passed exception. """ self._closing = True self._remove_reader() self._remove_writer() # Pending buffered data will not be written self._loop.call_soon(self._call_connection_lost, exc) def _call_connection_lost(self, exc): """Close the connection. Informs the protocol through connection_lost() and clears pending buffers and closes the serial connection. """ assert self._closing assert not self._has_writer assert not self._has_reader if os.name == "nt": self._serial.flush() else: try: self._serial.flush() except termios.error: # ignore termios errors which may happen if the serial device was # hot-unplugged. pass try: self._protocol.connection_lost(exc) finally: self._write_buffer.clear() self._serial.close() self._serial = None self._protocol = None self._loop = None @asyncio.coroutine def create_serial_connection(loop, protocol_factory, *args, **kwargs): ser = serial.serial_for_url(*args, **kwargs) protocol = protocol_factory() transport = SerialTransport(loop, protocol, ser) return (transport, protocol) @asyncio.coroutine def open_serial_connection(*, loop=None, limit=asyncio.streams._DEFAULT_LIMIT, **kwargs): """A wrapper for create_serial_connection() returning a (reader, writer) pair. The reader returned is a StreamReader instance; the writer is a StreamWriter instance. The arguments are all the usual arguments to Serial(). Additional optional keyword arguments are loop (to set the event loop instance to use) and limit (to set the buffer limit passed to the StreamReader. This function is a coroutine. """ if loop is None: loop = asyncio.get_event_loop() reader = asyncio.StreamReader(limit=limit, loop=loop) protocol = asyncio.StreamReaderProtocol(reader, loop=loop) transport, _ = yield from create_serial_connection( loop=loop, protocol_factory=lambda: protocol, **kwargs) writer = asyncio.StreamWriter(transport, protocol, reader, loop) return reader, writer # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # test if __name__ == '__main__': class Output(asyncio.Protocol): def __init__(self): super().__init__() self._transport = None def connection_made(self, transport): self._transport = transport print('port opened', self._transport) self._transport.serial.rts = False self._transport.write(b'Hello, World!\n') def data_received(self, data): print('data received', repr(data)) if b'\n' in data: self._transport.close() def connection_lost(self, exc): print('port closed') self._transport.loop.stop() def pause_writing(self): print('pause writing') print(self._transport.get_write_buffer_size()) def resume_writing(self): print(self._transport.get_write_buffer_size()) print('resume writing') loop = asyncio.get_event_loop() coro = create_serial_connection(loop, Output, '/dev/ttyUSB0', baudrate=115200) loop.run_until_complete(coro) loop.run_forever() loop.close() pyserial-asyncio-0.4/CREDITS.rst0000664000175000017500000000062613065546503016052 0ustar lchlch00000000000000========= Credits ========= Main authors of pySerial-asyncio ================================ - Chris Liechti (zsquareplusc) - Robert Smallshire (rob-smallshire) Contributors ============ - David Ko - Nicolas Di Pietro - jabdoa2 - Chris Seymour - ... not all names may be listed here, see also ``git log`` or online history_ .. _history: https://github.com/pyserial/pyserial-asyncio/commits/master pyserial-asyncio-0.4/README.rst0000664000175000017500000000151312777776551015727 0ustar lchlch00000000000000======================================== pyserial-asyncio |build-status| |docs| ======================================== Async I/O extension package for the Python Serial Port Extension for OSX, Linux, BSD It depends on pySerial and is compatible with Python 3.4 and later. Documentation ============= - Documentation: http://pyserial-asyncio.readthedocs.io/en/latest/ - Download Page: https://pypi.python.org/pypi/pyserial-asyncio - Project Homepage: https://github.com/pyserial/pyserial-asyncio .. |build-status| image:: https://travis-ci.org/pyserial/pyserial-asyncio.svg?branch=master :target: https://travis-ci.org/pyserial/pyserial-asyncio :alt: Build status .. |docs| image:: https://readthedocs.org/projects/pyserial-asyncio/badge/?version=latest :target: http://pyserial-asyncio.readthedocs.io/ :alt: Documentation pyserial-asyncio-0.4/requirements.txt0000664000175000017500000000002012777254547017510 0ustar lchlch00000000000000pyserial>=3.1.1