From 81e6fa2cec6c826ecad177b6b4b54553024a6413 Mon Sep 17 00:00:00 2001 From: qianyun210603 Date: Wed, 30 Jun 2021 16:47:16 +0800 Subject: [PATCH 1/4] decode on windows to return str instead of byte; use cbreak instead of raw to avoid additional space --- .coveragerc | 4 +- .flake8 | 4 +- .github/workflows/python-publish.yml | 62 +++--- .github/workflows/python-test.yml | 88 ++++---- .gitignore | 25 +-- .pre-commit-config.yaml | 34 +-- .travis.yml | 72 +++---- Makefile | 32 +-- README.rst | 310 +++++++++++++-------------- readchar/__init__.py | 8 +- readchar/key.py | 196 ++++++++--------- readchar/readchar_linux.py | 38 ++-- readchar/readchar_windows.py | 2 +- requirements-test.txt | 8 +- setup.cfg | 14 +- setup.py | 174 +++++++-------- test.py | 78 +++---- tests/unit/test_key.py | 34 +-- tests/unit/test_readkey.py | 108 +++++----- 19 files changed, 647 insertions(+), 644 deletions(-) diff --git a/.coveragerc b/.coveragerc index e7d592e..e448012 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1,2 +1,2 @@ -[run] -omit = */tests* +[run] +omit = */tests* diff --git a/.flake8 b/.flake8 index c057b0f..be6e8fa 100644 --- a/.flake8 +++ b/.flake8 @@ -1,2 +1,2 @@ -[flake8] -max-line-length=119 +[flake8] +max-line-length=119 diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index affc6a5..cad3475 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -1,31 +1,31 @@ -# This workflow will upload a Python Package using Twine when a release is created -# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries - -name: Upload Python Package - -on: - release: - types: [created] - -jobs: - deploy: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - name: Set up Python - uses: actions/setup-python@v2 - with: - python-version: '3.x' - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install setuptools wheel twine - - name: Build and publish - env: - TWINE_USERNAME: __token__ - TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }} - run: | - python setup.py sdist bdist_wheel - twine upload dist/* +# This workflow will upload a Python Package using Twine when a release is created +# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries + +name: Upload Python Package + +on: + release: + types: [created] + +jobs: + deploy: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: '3.x' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install setuptools wheel twine + - name: Build and publish + env: + TWINE_USERNAME: __token__ + TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }} + run: | + python setup.py sdist bdist_wheel + twine upload dist/* diff --git a/.github/workflows/python-test.yml b/.github/workflows/python-test.yml index 1996d19..d4f1060 100644 --- a/.github/workflows/python-test.yml +++ b/.github/workflows/python-test.yml @@ -1,44 +1,44 @@ -# This workflow will install Python dependencies, run tests and lint with a variety of Python versions -# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions - -name: Python package - -on: - push: - branches: [ master ] - pull_request: - branches: [ master ] - -jobs: - build: - - runs-on: ubuntu-latest - strategy: - matrix: - python-version: - - "2.7" - - "3.5" - - "3.6" - - "3.7" - - "3.8" - - "3.9" - - steps: - - uses: actions/checkout@v2 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - python -m pip install --upgrade pip - python -m pip install -r requirements-test.txt - - name: Lint with flake8 - run: | - # stop the build if there are Python syntax errors or undefined names - flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics - # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics - - name: Test with pytest - run: | - pytest +# This workflow will install Python dependencies, run tests and lint with a variety of Python versions +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions + +name: Python package + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build: + + runs-on: ubuntu-latest + strategy: + matrix: + python-version: + - "2.7" + - "3.5" + - "3.6" + - "3.7" + - "3.8" + - "3.9" + + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + python -m pip install -r requirements-test.txt + - name: Lint with flake8 + run: | + # stop the build if there are Python syntax errors or undefined names + flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics + # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide + flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + - name: Test with pytest + run: | + pytest diff --git a/.gitignore b/.gitignore index 4301da0..c8d4237 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,13 @@ -*~ -\#* -\.\#* -*.pyc -*.egg-info/ -build/ -dist/ -venv/ -.coverage -coverage.xml -.eggs -*.egg +*~ +\#* +\.\#* +*.pyc +*.egg-info/ +build/ +dist/ +venv/ +.coverage +coverage.xml +.eggs +*.egg +.idea/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5399570..f444074 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,17 +1,17 @@ -repos: - - repo: https://github.com/PyCQA/isort.git - rev: 5.7.0 - hooks: - - id: isort - - repo: https://github.com/psf/black - rev: 20.8b1 - hooks: - - id: black - language_version: python3 - args: - - -l - - "119" - - repo: https://gitlab.com/pycqa/flake8 - rev: 6de8252c035844f1e679f509b5f37340b44d5c39 - hooks: - - id: flake8 +repos: + - repo: https://github.com/PyCQA/isort.git + rev: 5.7.0 + hooks: + - id: isort + - repo: https://github.com/psf/black + rev: 20.8b1 + hooks: + - id: black + language_version: python3 + args: + - -l + - "119" + - repo: https://gitlab.com/pycqa/flake8 + rev: 6de8252c035844f1e679f509b5f37340b44d5c39 + hooks: + - id: flake8 diff --git a/.travis.yml b/.travis.yml index 5a93ab2..bd88a0a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,36 +1,36 @@ -language: python - -sudo: false - -python: - - "2.7" - - "3.4" - - "3.5" - - "3.6" - - "3.7-dev" - - "pypy" - - "pypy3" - -matrix: - include: - - python: "3.6" - env: TMODE=flake8 -env: - TMODE=test - -install: - - "if [[ $TMODE == 'test' ]]; then pip install pytest; fi" - - "if [[ $TMODE == 'test' ]]; then python setup.py install; fi" - - pip freeze --all - - ls -lh .eggs || true - -script: - - python setup.py $TMODE - -after_success: - - "if [[ $TMODE == 'test' ]]; then pip install python-coveralls; coveralls; fi" - -notifications: - email: - on_success: change - on_failure: change +language: python + +sudo: false + +python: + - "2.7" + - "3.4" + - "3.5" + - "3.6" + - "3.7-dev" + - "pypy" + - "pypy3" + +matrix: + include: + - python: "3.6" + env: TMODE=flake8 +env: + TMODE=test + +install: + - "if [[ $TMODE == 'test' ]]; then pip install pytest; fi" + - "if [[ $TMODE == 'test' ]]; then python setup.py install; fi" + - pip freeze --all + - ls -lh .eggs || true + +script: + - python setup.py $TMODE + +after_success: + - "if [[ $TMODE == 'test' ]]; then pip install python-coveralls; coveralls; fi" + +notifications: + email: + on_success: change + on_failure: change diff --git a/Makefile b/Makefile index 872a7f4..6038663 100644 --- a/Makefile +++ b/Makefile @@ -1,16 +1,16 @@ -all: flakes test - -test: - python setup.py test - -analysis:: flakes - -flakes: - @echo Searching for static errors... - @flake8 --statistics --count readchar - -coveralls:: - coveralls - -publish: - @python setup.py bdist_wheel upload +all: flakes test + +test: + python setup.py test + +analysis:: flakes + +flakes: + @echo Searching for static errors... + @flake8 --statistics --count readchar + +coveralls:: + coveralls + +publish: + @python setup.py bdist_wheel upload diff --git a/README.rst b/README.rst index 611cdac..0e67f25 100644 --- a/README.rst +++ b/README.rst @@ -1,155 +1,155 @@ -See it at: - -- `pypi`_ -- `GitHub`_ - -============== =============== ========= ============ -VERSION DOWNLOADS TESTS COVERAGE -============== =============== ========= ============ -|pip version| |pip downloads| |travis| |coveralls| -============== =============== ========= ============ - -Library to easily read single chars and key strokes. - -Goal and Philosophy -=================== - -Born as a `python-inquirer`_ requirement. - -The idea is to have a portable way to read **single** characters and **key-strokes**. - - -Documentation -============= - -Installation ------------- - -:: - - pip install readchar - -The :code:`readchar` library works with python 2.7, 3.4, 3.5, 3.6 and Pypy. - -Usage ------ - -Usage example: - -.. code:: python - - import readchar - - c = readchar.readchar() - key = readchar.readkey() - -API ----- - -There are just two methods: - -:code:`readchar()` -////////////////// - -Reads the next char from :code:`stdin`, returning it as a string with length 1. - - -:code:`readkey()` -///////////////// - -Reads the next key-stroke from :code:`stdin`, returning it as a string. - -A key-stroke can have: - -- 1 character for normal keys: 'a', 'z', '9'... -- 2 characters for combinations with ALT: ALT+A, ... -- 3 characters for cursors: ->, <-, ... -- 4 characters for combinations with CTRL and ALT: CTRL+ALT+SUPR, ... - -There is a list of previously captured chars with their names in :code:`readchar.key`, in order to be used in comparisons and so on. This list is not enough tested and it can have mistakes, so use it carefully. Please, report them if found. - - -OS Support ----------- - -Sadly, this library has only being probed on GNU/Linux. Please, if you can try it in another OS and find a bug, put an issue or send the pull-request. - -Thank you! - -How to contribute -================= - -You can download the code, make some changes with their tests, and make a pull-request. - -In order to develop or running the tests, you can do: - -1. Clone the repository. - -.. code:: bash - - git clone https://github.com/magmax/python-readchar.git - -2. Create a virtual environment: - -.. code:: bash - - virtualenv venv - -3. Enter in the virtual environment - -.. code:: bash - - source venv/bin/activate - -4. Install dependencies - -.. code:: bash - - pip install -r requirements-test.txt - -5. Run tests - -.. code:: bash - - make - - -Please, **Execute the tests before any pull-request**. This will avoid invalid builds. - - -License -======= - -Copyright (c) 2014-2021 Miguel Angel Garcia (`@magmax_en`_). - -Based on previous work on gist `getch()-like unbuffered character reading from stdin on both Windows and Unix (Python recipe)`_, started by `Danny Yoo`_. - -Licensed under `the MIT license`_. - - -.. |travis| image:: https://travis-ci.org/magmax/python-readchar.png - :target: `Travis`_ - :alt: Travis results - -.. |coveralls| image:: https://coveralls.io/repos/magmax/python-readchar/badge.png - :target: `Coveralls`_ - :alt: Coveralls results_ - -.. |pip version| image:: https://img.shields.io/pypi/v/readchar.svg - :target: https://pypi.python.org/pypi/readchar - :alt: Latest PyPI version - -.. |pip downloads| image:: https://img.shields.io/pypi/dm/readchar.svg - :target: https://pypi.python.org/pypi/readchar - :alt: Number of PyPI downloads - -.. _pypi: https://pypi.python.org/pypi/readchar -.. _GitHub: https://github.com/magmax/python-readchar -.. _python-inquirer: https://github.com/magmax/python-inquirer -.. _Travis: https://travis-ci.org/magmax/python-readchar -.. _Coveralls: https://coveralls.io/r/magmax/python-readchar -.. _@magmax_en: https://twitter.com/magmax_en - -.. _the MIT license: http://opensource.org/licenses/MIT -.. _getch()-like unbuffered character reading from stdin on both Windows and Unix (Python recipe): http://code.activestate.com/recipes/134892/ -.. _Danny Yoo: http://code.activestate.com/recipes/users/98032/ +See it at: + +- `pypi`_ +- `GitHub`_ + +============== =============== ========= ============ +VERSION DOWNLOADS TESTS COVERAGE +============== =============== ========= ============ +|pip version| |pip downloads| |travis| |coveralls| +============== =============== ========= ============ + +Library to easily read single chars and key strokes. + +Goal and Philosophy +=================== + +Born as a `python-inquirer`_ requirement. + +The idea is to have a portable way to read **single** characters and **key-strokes**. + + +Documentation +============= + +Installation +------------ + +:: + + pip install readchar + +The :code:`readchar` library works with python 2.7, 3.4, 3.5, 3.6 and Pypy. + +Usage +----- + +Usage example: + +.. code:: python + + import readchar + + c = readchar.readchar() + key = readchar.readkey() + +API +---- + +There are just two methods: + +:code:`readchar()` +////////////////// + +Reads the next char from :code:`stdin`, returning it as a string with length 1. + + +:code:`readkey()` +///////////////// + +Reads the next key-stroke from :code:`stdin`, returning it as a string. + +A key-stroke can have: + +- 1 character for normal keys: 'a', 'z', '9'... +- 2 characters for combinations with ALT: ALT+A, ... +- 3 characters for cursors: ->, <-, ... +- 4 characters for combinations with CTRL and ALT: CTRL+ALT+SUPR, ... + +There is a list of previously captured chars with their names in :code:`readchar.key`, in order to be used in comparisons and so on. This list is not enough tested and it can have mistakes, so use it carefully. Please, report them if found. + + +OS Support +---------- + +Sadly, this library has only being probed on GNU/Linux. Please, if you can try it in another OS and find a bug, put an issue or send the pull-request. + +Thank you! + +How to contribute +================= + +You can download the code, make some changes with their tests, and make a pull-request. + +In order to develop or running the tests, you can do: + +1. Clone the repository. + +.. code:: bash + + git clone https://github.com/magmax/python-readchar.git + +2. Create a virtual environment: + +.. code:: bash + + virtualenv venv + +3. Enter in the virtual environment + +.. code:: bash + + source venv/bin/activate + +4. Install dependencies + +.. code:: bash + + pip install -r requirements-test.txt + +5. Run tests + +.. code:: bash + + make + + +Please, **Execute the tests before any pull-request**. This will avoid invalid builds. + + +License +======= + +Copyright (c) 2014-2021 Miguel Angel Garcia (`@magmax_en`_). + +Based on previous work on gist `getch()-like unbuffered character reading from stdin on both Windows and Unix (Python recipe)`_, started by `Danny Yoo`_. + +Licensed under `the MIT license`_. + + +.. |travis| image:: https://travis-ci.org/magmax/python-readchar.png + :target: `Travis`_ + :alt: Travis results + +.. |coveralls| image:: https://coveralls.io/repos/magmax/python-readchar/badge.png + :target: `Coveralls`_ + :alt: Coveralls results_ + +.. |pip version| image:: https://img.shields.io/pypi/v/readchar.svg + :target: https://pypi.python.org/pypi/readchar + :alt: Latest PyPI version + +.. |pip downloads| image:: https://img.shields.io/pypi/dm/readchar.svg + :target: https://pypi.python.org/pypi/readchar + :alt: Number of PyPI downloads + +.. _pypi: https://pypi.python.org/pypi/readchar +.. _GitHub: https://github.com/magmax/python-readchar +.. _python-inquirer: https://github.com/magmax/python-inquirer +.. _Travis: https://travis-ci.org/magmax/python-readchar +.. _Coveralls: https://coveralls.io/r/magmax/python-readchar +.. _@magmax_en: https://twitter.com/magmax_en + +.. _the MIT license: http://opensource.org/licenses/MIT +.. _getch()-like unbuffered character reading from stdin on both Windows and Unix (Python recipe): http://code.activestate.com/recipes/134892/ +.. _Danny Yoo: http://code.activestate.com/recipes/users/98032/ diff --git a/readchar/__init__.py b/readchar/__init__.py index f4ffd5c..beea94f 100644 --- a/readchar/__init__.py +++ b/readchar/__init__.py @@ -1,4 +1,4 @@ -from . import key -from .readchar import readchar, readkey - -__all__ = [readchar, readkey, key] +from . import key +from .readchar import readchar, readkey + +__all__ = [readchar, readkey, key] diff --git a/readchar/key.py b/readchar/key.py index 8fb83da..f2833ee 100644 --- a/readchar/key.py +++ b/readchar/key.py @@ -1,98 +1,98 @@ -# common -LF = "\x0d" -CR = "\x0a" -ENTER = "\x0d" -BACKSPACE = "\x7f" -SUPR = "" -SPACE = "\x20" -ESC = "\x1b" - -# CTRL -CTRL_A = '\x01' -CTRL_B = '\x02' -CTRL_C = '\x03' -CTRL_D = '\x04' -CTRL_E = '\x05' -CTRL_F = '\x06' -CTRL_G = '\x07' -CTRL_H = '\x08' -CTRL_I = '\t' -CTRL_J = '\n' -CTRL_K = '\x0b' -CTRL_L = '\x0c' -CTRL_M = '\r' -CTRL_N = '\x0e' -CTRL_O = '\x0f' -CTRL_P = '\x10' -CTRL_Q = '\x11' -CTRL_R = '\x12' -CTRL_S = '\x13' -CTRL_T = '\x14' -CTRL_U = '\x15' -CTRL_V = '\x16' -CTRL_W = '\x17' -CTRL_X = '\x18' -CTRL_Y = '\x19' -CTRL_Z = '\x1a' - -# ALT -ALT_A = "\x1b\x61" - -# CTRL + ALT -CTRL_ALT_A = "\x1b\x01" - -# cursors -UP = "\x1b\x5b\x41" -DOWN = "\x1b\x5b\x42" -LEFT = "\x1b\x5b\x44" -RIGHT = "\x1b\x5b\x43" - -CTRL_ALT_SUPR = "\x1b\x5b\x33\x5e" - -# other -F1 = "\x1b\x4f\x50" -F2 = "\x1b\x4f\x51" -F3 = "\x1b\x4f\x52" -F4 = "\x1b\x4f\x53" -F5 = "\x1b\x4f\x31\x35\x7e" -F6 = "\x1b\x4f\x31\x37\x7e" -F7 = "\x1b\x4f\x31\x38\x7e" -F8 = "\x1b\x4f\x31\x39\x7e" -F9 = "\x1b\x4f\x32\x30\x7e" -F10 = "\x1b\x4f\x32\x31\x7e" -F11 = "\x1b\x4f\x32\x33\x7e" -F12 = "\x1b\x4f\x32\x34\x7e" - -PAGE_UP = "\x1b\x5b\x35\x7e" -PAGE_DOWN = "\x1b\x5b\x36\x7e" -HOME = "\x1b\x5b\x48" -END = "\x1b\x5b\x46" - -INSERT = "\x1b\x5b\x32\x7e" -SUPR = "\x1b\x5b\x33\x7e" - - -ESCAPE_SEQUENCES = ( - ESC, - ESC + "\x5b", - ESC + "\x5b" + "\x31", - ESC + "\x5b" + "\x32", - ESC + "\x5b" + "\x33", - ESC + "\x5b" + "\x35", - ESC + "\x5b" + "\x36", - ESC + "\x5b" + "\x31" + "\x35", - ESC + "\x5b" + "\x31" + "\x36", - ESC + "\x5b" + "\x31" + "\x37", - ESC + "\x5b" + "\x31" + "\x38", - ESC + "\x5b" + "\x31" + "\x39", - ESC + "\x5b" + "\x32" + "\x30", - ESC + "\x5b" + "\x32" + "\x31", - ESC + "\x5b" + "\x32" + "\x32", - ESC + "\x5b" + "\x32" + "\x33", - ESC + "\x5b" + "\x32" + "\x34", - ESC + "\x4f", - ESC + ESC, - ESC + ESC + "\x5b", - ESC + ESC + "\x5b" + "\x32", - ESC + ESC + "\x5b" + "\x33", -) +# common +LF = "\x0d" +CR = "\x0a" +ENTER = "\x0d" +BACKSPACE = "\x7f" +SUPR = "" +SPACE = "\x20" +ESC = "\x1b" + +# CTRL +CTRL_A = '\x01' +CTRL_B = '\x02' +CTRL_C = '\x03' +CTRL_D = '\x04' +CTRL_E = '\x05' +CTRL_F = '\x06' +CTRL_G = '\x07' +CTRL_H = '\x08' +CTRL_I = '\t' +CTRL_J = '\n' +CTRL_K = '\x0b' +CTRL_L = '\x0c' +CTRL_M = '\r' +CTRL_N = '\x0e' +CTRL_O = '\x0f' +CTRL_P = '\x10' +CTRL_Q = '\x11' +CTRL_R = '\x12' +CTRL_S = '\x13' +CTRL_T = '\x14' +CTRL_U = '\x15' +CTRL_V = '\x16' +CTRL_W = '\x17' +CTRL_X = '\x18' +CTRL_Y = '\x19' +CTRL_Z = '\x1a' + +# ALT +ALT_A = "\x1b\x61" + +# CTRL + ALT +CTRL_ALT_A = "\x1b\x01" + +# cursors +UP = "\x1b\x5b\x41" +DOWN = "\x1b\x5b\x42" +LEFT = "\x1b\x5b\x44" +RIGHT = "\x1b\x5b\x43" + +CTRL_ALT_SUPR = "\x1b\x5b\x33\x5e" + +# other +F1 = "\x1b\x4f\x50" +F2 = "\x1b\x4f\x51" +F3 = "\x1b\x4f\x52" +F4 = "\x1b\x4f\x53" +F5 = "\x1b\x4f\x31\x35\x7e" +F6 = "\x1b\x4f\x31\x37\x7e" +F7 = "\x1b\x4f\x31\x38\x7e" +F8 = "\x1b\x4f\x31\x39\x7e" +F9 = "\x1b\x4f\x32\x30\x7e" +F10 = "\x1b\x4f\x32\x31\x7e" +F11 = "\x1b\x4f\x32\x33\x7e" +F12 = "\x1b\x4f\x32\x34\x7e" + +PAGE_UP = "\x1b\x5b\x35\x7e" +PAGE_DOWN = "\x1b\x5b\x36\x7e" +HOME = "\x1b\x5b\x48" +END = "\x1b\x5b\x46" + +INSERT = "\x1b\x5b\x32\x7e" +SUPR = "\x1b\x5b\x33\x7e" + + +ESCAPE_SEQUENCES = ( + ESC, + ESC + "\x5b", + ESC + "\x5b" + "\x31", + ESC + "\x5b" + "\x32", + ESC + "\x5b" + "\x33", + ESC + "\x5b" + "\x35", + ESC + "\x5b" + "\x36", + ESC + "\x5b" + "\x31" + "\x35", + ESC + "\x5b" + "\x31" + "\x36", + ESC + "\x5b" + "\x31" + "\x37", + ESC + "\x5b" + "\x31" + "\x38", + ESC + "\x5b" + "\x31" + "\x39", + ESC + "\x5b" + "\x32" + "\x30", + ESC + "\x5b" + "\x32" + "\x31", + ESC + "\x5b" + "\x32" + "\x32", + ESC + "\x5b" + "\x32" + "\x33", + ESC + "\x5b" + "\x32" + "\x34", + ESC + "\x4f", + ESC + ESC, + ESC + ESC + "\x5b", + ESC + ESC + "\x5b" + "\x32", + ESC + ESC + "\x5b" + "\x33", +) diff --git a/readchar/readchar_linux.py b/readchar/readchar_linux.py index 6bcb4e2..df2c70c 100644 --- a/readchar/readchar_linux.py +++ b/readchar/readchar_linux.py @@ -1,18 +1,20 @@ -# -*- coding: utf-8 -*- -# Initially taken from: -# http://code.activestate.com/recipes/134892/ -# Thanks to Danny Yoo -import sys -import termios -import tty - - -def readchar(): - fd = sys.stdin.fileno() - old_settings = termios.tcgetattr(fd) - try: - tty.setraw(sys.stdin.fileno()) - ch = sys.stdin.read(1) - finally: - termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) - return ch +# -*- coding: utf-8 -*- +# Initially taken from: +# http://code.activestate.com/recipes/134892/ +# Thanks to Danny Yoo +import sys +import termios +import tty + + +def readchar(enter_code="\r"): + fd = sys.stdin.fileno() + old_settings = termios.tcgetattr(fd) + try: + tty.setcbreak(sys.stdin.fileno()) + ch = sys.stdin.read(1) + if ch in ('\r', '\n'): + ch = enter_code + finally: + termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) + return ch diff --git a/readchar/readchar_windows.py b/readchar/readchar_windows.py index 3afb4f8..c197a9a 100644 --- a/readchar/readchar_windows.py +++ b/readchar/readchar_windows.py @@ -24,4 +24,4 @@ def readchar(blocking=False): msvcrt.getch() ch = msvcrt.getch() - return ch if sys.version_info.major > 2 else ch.decode(encoding=win_encoding) + return ch.decode() if sys.version_info.major > 2 else ch.decode(encoding=win_encoding) diff --git a/requirements-test.txt b/requirements-test.txt index 462fa01..00cce81 100644 --- a/requirements-test.txt +++ b/requirements-test.txt @@ -1,4 +1,4 @@ -flake8 -pytest -pytest-cov - +flake8 +pytest +pytest-cov + diff --git a/setup.cfg b/setup.cfg index c59270b..ba07bfa 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,7 +1,7 @@ -[tool:pytest] -norecursedirs = .git venv build dist *egg -addopts = -rfEsxwX --cov readchar - -[flake8] -exclude = **/.*,venv/**,.eggs/** - +[tool:pytest] +norecursedirs = .git venv build dist *egg +addopts = -rfEsxwX --cov readchar + +[flake8] +exclude = **/.*,venv/**,.eggs/** + diff --git a/setup.py b/setup.py index e63b3b1..080a988 100644 --- a/setup.py +++ b/setup.py @@ -1,87 +1,87 @@ -# -*- coding: utf-8 -*- - -import os -import sys -from io import open - -from setuptools import find_packages, setup -from setuptools.command.test import test as TestCommand - -version = "2.0.1" -github_ref = os.getenv("GITHUB_REF") -if github_ref and github_ref.startswith("refs/tags"): - version = github_ref[10:] - - -def read_description(): - try: - with open("README.rst", encoding="utf8") as fd: - return fd.read() - except: # noqa - return "Error found retrieving description" - - -class PyTest(TestCommand): - user_options = [("pytest-args=", "a", "Arguments to pass to py.test")] - - def initialize_options(self): - TestCommand.initialize_options(self) - self.pytest_args = ["--cov-report=term-missing"] - - def finalize_options(self): - TestCommand.finalize_options(self) - self.test_args = [] - self.test_suite = True - - def run_tests(self): - # import here, cause outside the eggs aren't loaded - import pytest - - errno = pytest.main(self.pytest_args) - sys.exit(errno) - - -setup( - name="readchar", - version=version, - description="Utilities to read single characters and key-strokes", - long_description=read_description(), - classifiers=[ - "Development Status :: 5 - Production/Stable", - "Environment :: Console", - "Intended Audience :: Developers", - "License :: OSI Approved :: MIT License", - "Operating System :: OS Independent", - "Programming Language :: Python :: 2.7", - "Programming Language :: Python :: 3.4", - "Programming Language :: Python :: 3.5", - "Programming Language :: Python :: 3.6", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: Implementation :: CPython", - "Programming Language :: Python :: Implementation :: PyPy", - "Topic :: Software Development", - "Topic :: Software Development :: User Interfaces", - ], - keywords="stdin,command line", - author="Miguel Ángel García", - author_email="miguelangel.garcia@gmail.com", - url="https://github.com/magmax/python-readchar", - license="MIT", - packages=find_packages(exclude=["tests", "venv"]), - include_package_data=True, - zip_safe=False, - cmdclass={"test": PyTest}, - tests_require=[ - "pexpect", - "coverage", - "pytest", - "pytest-cov", - "wheel", - ], - install_requires=[], - setup_requires=[ - "flake8", - ], -) +# -*- coding: utf-8 -*- + +import os +import sys +from io import open + +from setuptools import find_packages, setup +from setuptools.command.test import test as TestCommand + +version = "2.0.1" +github_ref = os.getenv("GITHUB_REF") +if github_ref and github_ref.startswith("refs/tags"): + version = github_ref[10:] + + +def read_description(): + try: + with open("README.rst", encoding="utf8") as fd: + return fd.read() + except: # noqa + return "Error found retrieving description" + + +class PyTest(TestCommand): + user_options = [("pytest-args=", "a", "Arguments to pass to py.test")] + + def initialize_options(self): + TestCommand.initialize_options(self) + self.pytest_args = ["--cov-report=term-missing"] + + def finalize_options(self): + TestCommand.finalize_options(self) + self.test_args = [] + self.test_suite = True + + def run_tests(self): + # import here, cause outside the eggs aren't loaded + import pytest + + errno = pytest.main(self.pytest_args) + sys.exit(errno) + + +setup( + name="readchar", + version=version, + description="Utilities to read single characters and key-strokes", + long_description=read_description(), + classifiers=[ + "Development Status :: 5 - Production/Stable", + "Environment :: Console", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", + "Programming Language :: Python :: 2.7", + "Programming Language :: Python :: 3.4", + "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", + "Topic :: Software Development", + "Topic :: Software Development :: User Interfaces", + ], + keywords="stdin,command line", + author="Miguel Ángel García", + author_email="miguelangel.garcia@gmail.com", + url="https://github.com/magmax/python-readchar", + license="MIT", + packages=find_packages(exclude=["tests", "venv"]), + include_package_data=True, + zip_safe=False, + cmdclass={"test": PyTest}, + tests_require=[ + "pexpect", + "coverage", + "pytest", + "pytest-cov", + "wheel", + ], + install_requires=[], + setup_requires=[ + "flake8", + ], +) diff --git a/test.py b/test.py index d78b18f..98155e5 100644 --- a/test.py +++ b/test.py @@ -1,39 +1,39 @@ -import readchar.key -import readchar.readchar - -decode_dict = { - readchar.key.ESC: "ESC", - readchar.key.UP: "UP", - readchar.key.DOWN: "DOWN", - readchar.key.LEFT: "LEFT", - readchar.key.RIGHT: "RIGHT", - readchar.key.PAGE_UP: "PAGE_UP", - readchar.key.PAGE_DOWN: "PAGE_DOWN", - readchar.key.HOME: "HOME", - readchar.key.END: "END", - readchar.key.INSERT: "INSERT", - readchar.key.SUPR: "DELETE", - readchar.key.F1: "F1", - readchar.key.F2: "F2", - readchar.key.F3: "F3", - readchar.key.F4: "F4", - readchar.key.F5: "F5", - readchar.key.F6: "F6", - readchar.key.F7: "F7", - readchar.key.F8: "F8", - readchar.key.F9: "F9", - readchar.key.F10: "F10", - readchar.key.F12: "F12", - readchar.key.ALT_A: "ALT_A", -} - -while True: - c = readchar.readkey() - - if c in decode_dict: - print("got {}".format(decode_dict[c])) - else: - print(c) - - if c == "d": - break +import readchar.key +import readchar.readchar + +decode_dict = { + readchar.key.ESC: "ESC", + readchar.key.UP: "UP", + readchar.key.DOWN: "DOWN", + readchar.key.LEFT: "LEFT", + readchar.key.RIGHT: "RIGHT", + readchar.key.PAGE_UP: "PAGE_UP", + readchar.key.PAGE_DOWN: "PAGE_DOWN", + readchar.key.HOME: "HOME", + readchar.key.END: "END", + readchar.key.INSERT: "INSERT", + readchar.key.SUPR: "DELETE", + readchar.key.F1: "F1", + readchar.key.F2: "F2", + readchar.key.F3: "F3", + readchar.key.F4: "F4", + readchar.key.F5: "F5", + readchar.key.F6: "F6", + readchar.key.F7: "F7", + readchar.key.F8: "F8", + readchar.key.F9: "F9", + readchar.key.F10: "F10", + readchar.key.F12: "F12", + readchar.key.ALT_A: "ALT_A", +} + +while True: + c = readchar.readkey() + + if c in decode_dict: + print("got {}".format(decode_dict[c])) + else: + print(c) + + if c == "d": + break diff --git a/tests/unit/test_key.py b/tests/unit/test_key.py index ef605f3..e669e6a 100644 --- a/tests/unit/test_key.py +++ b/tests/unit/test_key.py @@ -1,17 +1,17 @@ -import unittest - -from readchar import key - - -class KeyTest(unittest.TestCase): - def test_character_length_1(self): - self.assertEqual(1, len(key.CTRL_A)) - - def test_character_length_2(self): - self.assertEqual(2, len(key.ALT_A)) - - def test_character_length_3(self): - self.assertEqual(3, len(key.UP)) - - def test_character_length_4(self): - self.assertEqual(4, len(key.CTRL_ALT_SUPR)) +import unittest + +from readchar import key + + +class KeyTest(unittest.TestCase): + def test_character_length_1(self): + self.assertEqual(1, len(key.CTRL_A)) + + def test_character_length_2(self): + self.assertEqual(2, len(key.ALT_A)) + + def test_character_length_3(self): + self.assertEqual(3, len(key.UP)) + + def test_character_length_4(self): + self.assertEqual(4, len(key.CTRL_ALT_SUPR)) diff --git a/tests/unit/test_readkey.py b/tests/unit/test_readkey.py index 5f52727..d8968f3 100644 --- a/tests/unit/test_readkey.py +++ b/tests/unit/test_readkey.py @@ -1,54 +1,54 @@ -import unittest - -from readchar import readkey - - -def readchar_fn_factory(stream): - - v = [x for x in stream] - - def inner(): - return v.pop(0) - - return inner - - -class ReadKeyTest(unittest.TestCase): - def test_basic_character(self): - getchar_fn = readchar_fn_factory("a") - - result = readkey(getchar_fn) - - self.assertEqual("a", result) - - def test_string_instead_of_char(self): - char = "a" - getchar_fn = readchar_fn_factory(char + "bcde") - - result = readkey(getchar_fn) - - self.assertEqual(char, result) - - def test_special_combo_character(self): - char = "\x1b\x01" - getchar_fn = readchar_fn_factory(char + "foo") - - result = readkey(getchar_fn) - - self.assertEqual(char, result) - - def test_special_key(self): - char = "\x1b\x5b\x41" - getchar_fn = readchar_fn_factory(char + "foo") - - result = readkey(getchar_fn) - - self.assertEqual(char, result) - - def test_special_key_combo(self): - char = "\x1b\x5b\x33\x5e" - getchar_fn = readchar_fn_factory(char + "foo") - - result = readkey(getchar_fn) - - self.assertEqual(char, result) +import unittest + +from readchar import readkey + + +def readchar_fn_factory(stream): + + v = [x for x in stream] + + def inner(): + return v.pop(0) + + return inner + + +class ReadKeyTest(unittest.TestCase): + def test_basic_character(self): + getchar_fn = readchar_fn_factory("a") + + result = readkey(getchar_fn) + + self.assertEqual("a", result) + + def test_string_instead_of_char(self): + char = "a" + getchar_fn = readchar_fn_factory(char + "bcde") + + result = readkey(getchar_fn) + + self.assertEqual(char, result) + + def test_special_combo_character(self): + char = "\x1b\x01" + getchar_fn = readchar_fn_factory(char + "foo") + + result = readkey(getchar_fn) + + self.assertEqual(char, result) + + def test_special_key(self): + char = "\x1b\x5b\x41" + getchar_fn = readchar_fn_factory(char + "foo") + + result = readkey(getchar_fn) + + self.assertEqual(char, result) + + def test_special_key_combo(self): + char = "\x1b\x5b\x33\x5e" + getchar_fn = readchar_fn_factory(char + "foo") + + result = readkey(getchar_fn) + + self.assertEqual(char, result) From 7e28e069c7ccfd529d1c6aeab12c5e5bfcf9c309 Mon Sep 17 00:00:00 2001 From: root Date: Tue, 13 Jul 2021 09:24:19 +0200 Subject: [PATCH 2/4] dos to unix --- Makefile | 32 ++-- README.rst | 310 +++++++++++++++++------------------ readchar/__init__.py | 8 +- readchar/key.py | 196 +++++++++++----------- readchar/readchar.py | 194 +++++++++++----------- readchar/readchar_linux.py | 40 ++--- readchar/readchar_windows.py | 54 +++--- requirements-test.txt | 8 +- setup.cfg | 14 +- setup.py | 174 ++++++++++---------- test.py | 78 ++++----- 11 files changed, 554 insertions(+), 554 deletions(-) diff --git a/Makefile b/Makefile index 6038663..872a7f4 100644 --- a/Makefile +++ b/Makefile @@ -1,16 +1,16 @@ -all: flakes test - -test: - python setup.py test - -analysis:: flakes - -flakes: - @echo Searching for static errors... - @flake8 --statistics --count readchar - -coveralls:: - coveralls - -publish: - @python setup.py bdist_wheel upload +all: flakes test + +test: + python setup.py test + +analysis:: flakes + +flakes: + @echo Searching for static errors... + @flake8 --statistics --count readchar + +coveralls:: + coveralls + +publish: + @python setup.py bdist_wheel upload diff --git a/README.rst b/README.rst index 0e67f25..611cdac 100644 --- a/README.rst +++ b/README.rst @@ -1,155 +1,155 @@ -See it at: - -- `pypi`_ -- `GitHub`_ - -============== =============== ========= ============ -VERSION DOWNLOADS TESTS COVERAGE -============== =============== ========= ============ -|pip version| |pip downloads| |travis| |coveralls| -============== =============== ========= ============ - -Library to easily read single chars and key strokes. - -Goal and Philosophy -=================== - -Born as a `python-inquirer`_ requirement. - -The idea is to have a portable way to read **single** characters and **key-strokes**. - - -Documentation -============= - -Installation ------------- - -:: - - pip install readchar - -The :code:`readchar` library works with python 2.7, 3.4, 3.5, 3.6 and Pypy. - -Usage ------ - -Usage example: - -.. code:: python - - import readchar - - c = readchar.readchar() - key = readchar.readkey() - -API ----- - -There are just two methods: - -:code:`readchar()` -////////////////// - -Reads the next char from :code:`stdin`, returning it as a string with length 1. - - -:code:`readkey()` -///////////////// - -Reads the next key-stroke from :code:`stdin`, returning it as a string. - -A key-stroke can have: - -- 1 character for normal keys: 'a', 'z', '9'... -- 2 characters for combinations with ALT: ALT+A, ... -- 3 characters for cursors: ->, <-, ... -- 4 characters for combinations with CTRL and ALT: CTRL+ALT+SUPR, ... - -There is a list of previously captured chars with their names in :code:`readchar.key`, in order to be used in comparisons and so on. This list is not enough tested and it can have mistakes, so use it carefully. Please, report them if found. - - -OS Support ----------- - -Sadly, this library has only being probed on GNU/Linux. Please, if you can try it in another OS and find a bug, put an issue or send the pull-request. - -Thank you! - -How to contribute -================= - -You can download the code, make some changes with their tests, and make a pull-request. - -In order to develop or running the tests, you can do: - -1. Clone the repository. - -.. code:: bash - - git clone https://github.com/magmax/python-readchar.git - -2. Create a virtual environment: - -.. code:: bash - - virtualenv venv - -3. Enter in the virtual environment - -.. code:: bash - - source venv/bin/activate - -4. Install dependencies - -.. code:: bash - - pip install -r requirements-test.txt - -5. Run tests - -.. code:: bash - - make - - -Please, **Execute the tests before any pull-request**. This will avoid invalid builds. - - -License -======= - -Copyright (c) 2014-2021 Miguel Angel Garcia (`@magmax_en`_). - -Based on previous work on gist `getch()-like unbuffered character reading from stdin on both Windows and Unix (Python recipe)`_, started by `Danny Yoo`_. - -Licensed under `the MIT license`_. - - -.. |travis| image:: https://travis-ci.org/magmax/python-readchar.png - :target: `Travis`_ - :alt: Travis results - -.. |coveralls| image:: https://coveralls.io/repos/magmax/python-readchar/badge.png - :target: `Coveralls`_ - :alt: Coveralls results_ - -.. |pip version| image:: https://img.shields.io/pypi/v/readchar.svg - :target: https://pypi.python.org/pypi/readchar - :alt: Latest PyPI version - -.. |pip downloads| image:: https://img.shields.io/pypi/dm/readchar.svg - :target: https://pypi.python.org/pypi/readchar - :alt: Number of PyPI downloads - -.. _pypi: https://pypi.python.org/pypi/readchar -.. _GitHub: https://github.com/magmax/python-readchar -.. _python-inquirer: https://github.com/magmax/python-inquirer -.. _Travis: https://travis-ci.org/magmax/python-readchar -.. _Coveralls: https://coveralls.io/r/magmax/python-readchar -.. _@magmax_en: https://twitter.com/magmax_en - -.. _the MIT license: http://opensource.org/licenses/MIT -.. _getch()-like unbuffered character reading from stdin on both Windows and Unix (Python recipe): http://code.activestate.com/recipes/134892/ -.. _Danny Yoo: http://code.activestate.com/recipes/users/98032/ +See it at: + +- `pypi`_ +- `GitHub`_ + +============== =============== ========= ============ +VERSION DOWNLOADS TESTS COVERAGE +============== =============== ========= ============ +|pip version| |pip downloads| |travis| |coveralls| +============== =============== ========= ============ + +Library to easily read single chars and key strokes. + +Goal and Philosophy +=================== + +Born as a `python-inquirer`_ requirement. + +The idea is to have a portable way to read **single** characters and **key-strokes**. + + +Documentation +============= + +Installation +------------ + +:: + + pip install readchar + +The :code:`readchar` library works with python 2.7, 3.4, 3.5, 3.6 and Pypy. + +Usage +----- + +Usage example: + +.. code:: python + + import readchar + + c = readchar.readchar() + key = readchar.readkey() + +API +---- + +There are just two methods: + +:code:`readchar()` +////////////////// + +Reads the next char from :code:`stdin`, returning it as a string with length 1. + + +:code:`readkey()` +///////////////// + +Reads the next key-stroke from :code:`stdin`, returning it as a string. + +A key-stroke can have: + +- 1 character for normal keys: 'a', 'z', '9'... +- 2 characters for combinations with ALT: ALT+A, ... +- 3 characters for cursors: ->, <-, ... +- 4 characters for combinations with CTRL and ALT: CTRL+ALT+SUPR, ... + +There is a list of previously captured chars with their names in :code:`readchar.key`, in order to be used in comparisons and so on. This list is not enough tested and it can have mistakes, so use it carefully. Please, report them if found. + + +OS Support +---------- + +Sadly, this library has only being probed on GNU/Linux. Please, if you can try it in another OS and find a bug, put an issue or send the pull-request. + +Thank you! + +How to contribute +================= + +You can download the code, make some changes with their tests, and make a pull-request. + +In order to develop or running the tests, you can do: + +1. Clone the repository. + +.. code:: bash + + git clone https://github.com/magmax/python-readchar.git + +2. Create a virtual environment: + +.. code:: bash + + virtualenv venv + +3. Enter in the virtual environment + +.. code:: bash + + source venv/bin/activate + +4. Install dependencies + +.. code:: bash + + pip install -r requirements-test.txt + +5. Run tests + +.. code:: bash + + make + + +Please, **Execute the tests before any pull-request**. This will avoid invalid builds. + + +License +======= + +Copyright (c) 2014-2021 Miguel Angel Garcia (`@magmax_en`_). + +Based on previous work on gist `getch()-like unbuffered character reading from stdin on both Windows and Unix (Python recipe)`_, started by `Danny Yoo`_. + +Licensed under `the MIT license`_. + + +.. |travis| image:: https://travis-ci.org/magmax/python-readchar.png + :target: `Travis`_ + :alt: Travis results + +.. |coveralls| image:: https://coveralls.io/repos/magmax/python-readchar/badge.png + :target: `Coveralls`_ + :alt: Coveralls results_ + +.. |pip version| image:: https://img.shields.io/pypi/v/readchar.svg + :target: https://pypi.python.org/pypi/readchar + :alt: Latest PyPI version + +.. |pip downloads| image:: https://img.shields.io/pypi/dm/readchar.svg + :target: https://pypi.python.org/pypi/readchar + :alt: Number of PyPI downloads + +.. _pypi: https://pypi.python.org/pypi/readchar +.. _GitHub: https://github.com/magmax/python-readchar +.. _python-inquirer: https://github.com/magmax/python-inquirer +.. _Travis: https://travis-ci.org/magmax/python-readchar +.. _Coveralls: https://coveralls.io/r/magmax/python-readchar +.. _@magmax_en: https://twitter.com/magmax_en + +.. _the MIT license: http://opensource.org/licenses/MIT +.. _getch()-like unbuffered character reading from stdin on both Windows and Unix (Python recipe): http://code.activestate.com/recipes/134892/ +.. _Danny Yoo: http://code.activestate.com/recipes/users/98032/ diff --git a/readchar/__init__.py b/readchar/__init__.py index beea94f..f4ffd5c 100644 --- a/readchar/__init__.py +++ b/readchar/__init__.py @@ -1,4 +1,4 @@ -from . import key -from .readchar import readchar, readkey - -__all__ = [readchar, readkey, key] +from . import key +from .readchar import readchar, readkey + +__all__ = [readchar, readkey, key] diff --git a/readchar/key.py b/readchar/key.py index f2833ee..8fb83da 100644 --- a/readchar/key.py +++ b/readchar/key.py @@ -1,98 +1,98 @@ -# common -LF = "\x0d" -CR = "\x0a" -ENTER = "\x0d" -BACKSPACE = "\x7f" -SUPR = "" -SPACE = "\x20" -ESC = "\x1b" - -# CTRL -CTRL_A = '\x01' -CTRL_B = '\x02' -CTRL_C = '\x03' -CTRL_D = '\x04' -CTRL_E = '\x05' -CTRL_F = '\x06' -CTRL_G = '\x07' -CTRL_H = '\x08' -CTRL_I = '\t' -CTRL_J = '\n' -CTRL_K = '\x0b' -CTRL_L = '\x0c' -CTRL_M = '\r' -CTRL_N = '\x0e' -CTRL_O = '\x0f' -CTRL_P = '\x10' -CTRL_Q = '\x11' -CTRL_R = '\x12' -CTRL_S = '\x13' -CTRL_T = '\x14' -CTRL_U = '\x15' -CTRL_V = '\x16' -CTRL_W = '\x17' -CTRL_X = '\x18' -CTRL_Y = '\x19' -CTRL_Z = '\x1a' - -# ALT -ALT_A = "\x1b\x61" - -# CTRL + ALT -CTRL_ALT_A = "\x1b\x01" - -# cursors -UP = "\x1b\x5b\x41" -DOWN = "\x1b\x5b\x42" -LEFT = "\x1b\x5b\x44" -RIGHT = "\x1b\x5b\x43" - -CTRL_ALT_SUPR = "\x1b\x5b\x33\x5e" - -# other -F1 = "\x1b\x4f\x50" -F2 = "\x1b\x4f\x51" -F3 = "\x1b\x4f\x52" -F4 = "\x1b\x4f\x53" -F5 = "\x1b\x4f\x31\x35\x7e" -F6 = "\x1b\x4f\x31\x37\x7e" -F7 = "\x1b\x4f\x31\x38\x7e" -F8 = "\x1b\x4f\x31\x39\x7e" -F9 = "\x1b\x4f\x32\x30\x7e" -F10 = "\x1b\x4f\x32\x31\x7e" -F11 = "\x1b\x4f\x32\x33\x7e" -F12 = "\x1b\x4f\x32\x34\x7e" - -PAGE_UP = "\x1b\x5b\x35\x7e" -PAGE_DOWN = "\x1b\x5b\x36\x7e" -HOME = "\x1b\x5b\x48" -END = "\x1b\x5b\x46" - -INSERT = "\x1b\x5b\x32\x7e" -SUPR = "\x1b\x5b\x33\x7e" - - -ESCAPE_SEQUENCES = ( - ESC, - ESC + "\x5b", - ESC + "\x5b" + "\x31", - ESC + "\x5b" + "\x32", - ESC + "\x5b" + "\x33", - ESC + "\x5b" + "\x35", - ESC + "\x5b" + "\x36", - ESC + "\x5b" + "\x31" + "\x35", - ESC + "\x5b" + "\x31" + "\x36", - ESC + "\x5b" + "\x31" + "\x37", - ESC + "\x5b" + "\x31" + "\x38", - ESC + "\x5b" + "\x31" + "\x39", - ESC + "\x5b" + "\x32" + "\x30", - ESC + "\x5b" + "\x32" + "\x31", - ESC + "\x5b" + "\x32" + "\x32", - ESC + "\x5b" + "\x32" + "\x33", - ESC + "\x5b" + "\x32" + "\x34", - ESC + "\x4f", - ESC + ESC, - ESC + ESC + "\x5b", - ESC + ESC + "\x5b" + "\x32", - ESC + ESC + "\x5b" + "\x33", -) +# common +LF = "\x0d" +CR = "\x0a" +ENTER = "\x0d" +BACKSPACE = "\x7f" +SUPR = "" +SPACE = "\x20" +ESC = "\x1b" + +# CTRL +CTRL_A = '\x01' +CTRL_B = '\x02' +CTRL_C = '\x03' +CTRL_D = '\x04' +CTRL_E = '\x05' +CTRL_F = '\x06' +CTRL_G = '\x07' +CTRL_H = '\x08' +CTRL_I = '\t' +CTRL_J = '\n' +CTRL_K = '\x0b' +CTRL_L = '\x0c' +CTRL_M = '\r' +CTRL_N = '\x0e' +CTRL_O = '\x0f' +CTRL_P = '\x10' +CTRL_Q = '\x11' +CTRL_R = '\x12' +CTRL_S = '\x13' +CTRL_T = '\x14' +CTRL_U = '\x15' +CTRL_V = '\x16' +CTRL_W = '\x17' +CTRL_X = '\x18' +CTRL_Y = '\x19' +CTRL_Z = '\x1a' + +# ALT +ALT_A = "\x1b\x61" + +# CTRL + ALT +CTRL_ALT_A = "\x1b\x01" + +# cursors +UP = "\x1b\x5b\x41" +DOWN = "\x1b\x5b\x42" +LEFT = "\x1b\x5b\x44" +RIGHT = "\x1b\x5b\x43" + +CTRL_ALT_SUPR = "\x1b\x5b\x33\x5e" + +# other +F1 = "\x1b\x4f\x50" +F2 = "\x1b\x4f\x51" +F3 = "\x1b\x4f\x52" +F4 = "\x1b\x4f\x53" +F5 = "\x1b\x4f\x31\x35\x7e" +F6 = "\x1b\x4f\x31\x37\x7e" +F7 = "\x1b\x4f\x31\x38\x7e" +F8 = "\x1b\x4f\x31\x39\x7e" +F9 = "\x1b\x4f\x32\x30\x7e" +F10 = "\x1b\x4f\x32\x31\x7e" +F11 = "\x1b\x4f\x32\x33\x7e" +F12 = "\x1b\x4f\x32\x34\x7e" + +PAGE_UP = "\x1b\x5b\x35\x7e" +PAGE_DOWN = "\x1b\x5b\x36\x7e" +HOME = "\x1b\x5b\x48" +END = "\x1b\x5b\x46" + +INSERT = "\x1b\x5b\x32\x7e" +SUPR = "\x1b\x5b\x33\x7e" + + +ESCAPE_SEQUENCES = ( + ESC, + ESC + "\x5b", + ESC + "\x5b" + "\x31", + ESC + "\x5b" + "\x32", + ESC + "\x5b" + "\x33", + ESC + "\x5b" + "\x35", + ESC + "\x5b" + "\x36", + ESC + "\x5b" + "\x31" + "\x35", + ESC + "\x5b" + "\x31" + "\x36", + ESC + "\x5b" + "\x31" + "\x37", + ESC + "\x5b" + "\x31" + "\x38", + ESC + "\x5b" + "\x31" + "\x39", + ESC + "\x5b" + "\x32" + "\x30", + ESC + "\x5b" + "\x32" + "\x31", + ESC + "\x5b" + "\x32" + "\x32", + ESC + "\x5b" + "\x32" + "\x33", + ESC + "\x5b" + "\x32" + "\x34", + ESC + "\x4f", + ESC + ESC, + ESC + ESC + "\x5b", + ESC + ESC + "\x5b" + "\x32", + ESC + ESC + "\x5b" + "\x33", +) diff --git a/readchar/readchar.py b/readchar/readchar.py index fc35429..652d6b9 100644 --- a/readchar/readchar.py +++ b/readchar/readchar.py @@ -1,97 +1,97 @@ -# -*- coding: utf-8 -*- -# This file is based on this gist: -# http://code.activestate.com/recipes/134892/ -# So real authors are DannyYoo and company. -import sys - -if sys.platform.startswith("linux"): - from .readchar_linux import readchar -elif sys.platform == "darwin": - from .readchar_linux import readchar -elif sys.platform in ("win32", "cygwin"): - import msvcrt - - from . import key - from .readchar_windows import readchar -else: - raise NotImplementedError("The platform %s is not supported yet" % sys.platform) - - -if sys.platform in ("win32", "cygwin"): - # - # Windows uses scan codes for extended characters. The ordinal returned is - # 256 * the scan code. This dictionary translates scan codes to the - # unicode sequences expected by readkey. - # - # for windows scan codes see: - # https://msdn.microsoft.com/en-us/library/aa299374 - # or - # http://www.quadibloc.com/comp/scan.htm - xlate_dict = { - 13: key.ENTER, - 27: key.ESC, - 15104: key.F1, - 15360: key.F2, - 15616: key.F3, - 15872: key.F4, - 16128: key.F5, - 16384: key.F6, - 16640: key.F7, - 16896: key.F8, - 17152: key.F9, - 17408: key.F10, - 22272: key.F11, - 34528: key.F12, - 7680: key.ALT_A, - # don't have table entries for... - # CTRL_ALT_A, # Ctrl-Alt-A, etc. - # CTRL_ALT_SUPR, - # CTRL-F1 - 21216: key.INSERT, - 21472: key.SUPR, # key.py uses SUPR, not DELETE - 18912: key.PAGE_UP, - 20960: key.PAGE_DOWN, - 18400: key.HOME, - 20448: key.END, - 18656: key.UP, - 20704: key.DOWN, - 19424: key.LEFT, - 19936: key.RIGHT, - } - - def readkey(getchar_fn=None): - # Get a single character on Windows. if an extended key is pressed, the - # Windows scan code is translated into a the unicode sequences readchar - # expects (see key.py). - while True: - if msvcrt.kbhit(): - ch = msvcrt.getch() - a = ord(ch) - if a == 0 or a == 224: - b = ord(msvcrt.getch()) - x = a + (b * 256) - - try: - return xlate_dict[x] - except KeyError: - return None - return x - else: - return ch.decode() - - -else: - - def readkey(getchar_fn=None): - getchar = getchar_fn or readchar - c1 = getchar() - if ord(c1) != 0x1B: - return c1 - c2 = getchar() - if ord(c2) != 0x5B: - return c1 + c2 - c3 = getchar() - if ord(c3) != 0x33: - return c1 + c2 + c3 - c4 = getchar() - return c1 + c2 + c3 + c4 +# -*- coding: utf-8 -*- +# This file is based on this gist: +# http://code.activestate.com/recipes/134892/ +# So real authors are DannyYoo and company. +import sys + +if sys.platform.startswith("linux"): + from .readchar_linux import readchar +elif sys.platform == "darwin": + from .readchar_linux import readchar +elif sys.platform in ("win32", "cygwin"): + import msvcrt + + from . import key + from .readchar_windows import readchar +else: + raise NotImplementedError("The platform %s is not supported yet" % sys.platform) + + +if sys.platform in ("win32", "cygwin"): + # + # Windows uses scan codes for extended characters. The ordinal returned is + # 256 * the scan code. This dictionary translates scan codes to the + # unicode sequences expected by readkey. + # + # for windows scan codes see: + # https://msdn.microsoft.com/en-us/library/aa299374 + # or + # http://www.quadibloc.com/comp/scan.htm + xlate_dict = { + 13: key.ENTER, + 27: key.ESC, + 15104: key.F1, + 15360: key.F2, + 15616: key.F3, + 15872: key.F4, + 16128: key.F5, + 16384: key.F6, + 16640: key.F7, + 16896: key.F8, + 17152: key.F9, + 17408: key.F10, + 22272: key.F11, + 34528: key.F12, + 7680: key.ALT_A, + # don't have table entries for... + # CTRL_ALT_A, # Ctrl-Alt-A, etc. + # CTRL_ALT_SUPR, + # CTRL-F1 + 21216: key.INSERT, + 21472: key.SUPR, # key.py uses SUPR, not DELETE + 18912: key.PAGE_UP, + 20960: key.PAGE_DOWN, + 18400: key.HOME, + 20448: key.END, + 18656: key.UP, + 20704: key.DOWN, + 19424: key.LEFT, + 19936: key.RIGHT, + } + + def readkey(getchar_fn=None): + # Get a single character on Windows. if an extended key is pressed, the + # Windows scan code is translated into a the unicode sequences readchar + # expects (see key.py). + while True: + if msvcrt.kbhit(): + ch = msvcrt.getch() + a = ord(ch) + if a == 0 or a == 224: + b = ord(msvcrt.getch()) + x = a + (b * 256) + + try: + return xlate_dict[x] + except KeyError: + return None + return x + else: + return ch.decode() + + +else: + + def readkey(getchar_fn=None): + getchar = getchar_fn or readchar + c1 = getchar() + if ord(c1) != 0x1B: + return c1 + c2 = getchar() + if ord(c2) != 0x5B: + return c1 + c2 + c3 = getchar() + if ord(c3) != 0x33: + return c1 + c2 + c3 + c4 = getchar() + return c1 + c2 + c3 + c4 diff --git a/readchar/readchar_linux.py b/readchar/readchar_linux.py index df2c70c..6301bca 100644 --- a/readchar/readchar_linux.py +++ b/readchar/readchar_linux.py @@ -1,20 +1,20 @@ -# -*- coding: utf-8 -*- -# Initially taken from: -# http://code.activestate.com/recipes/134892/ -# Thanks to Danny Yoo -import sys -import termios -import tty - - -def readchar(enter_code="\r"): - fd = sys.stdin.fileno() - old_settings = termios.tcgetattr(fd) - try: - tty.setcbreak(sys.stdin.fileno()) - ch = sys.stdin.read(1) - if ch in ('\r', '\n'): - ch = enter_code - finally: - termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) - return ch +# -*- coding: utf-8 -*- +# Initially taken from: +# http://code.activestate.com/recipes/134892/ +# Thanks to Danny Yoo +import sys +import termios +import tty + + +def readchar(enter_code="\r"): + fd = sys.stdin.fileno() + old_settings = termios.tcgetattr(fd) + try: + tty.setcbreak(sys.stdin.fileno()) + ch = sys.stdin.read(1) + if ch in ('\r', '\n'): + ch = enter_code + finally: + termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) + return ch diff --git a/readchar/readchar_windows.py b/readchar/readchar_windows.py index c197a9a..04de626 100644 --- a/readchar/readchar_windows.py +++ b/readchar/readchar_windows.py @@ -1,27 +1,27 @@ -# -*- coding: utf-8 -*- -# Initially taken from: -# http://code.activestate.com/recipes/134892/#c9 -# Thanks to Stephen Chappell -import msvcrt -import sys - -win_encoding = "mbcs" - - -XE0_OR_00 = "\x00\xe0" - - -def readchar(blocking=False): - "Get a single character on Windows." - - while msvcrt.kbhit(): - msvcrt.getch() - ch = msvcrt.getch() - # print('ch={}, type(ch)={}'.format(ch, type(ch))) - # while ch.decode(win_encoding) in unicode('\x00\xe0', win_encoding): - while ch.decode(win_encoding) in XE0_OR_00: - # print('found x00 or xe0') - msvcrt.getch() - ch = msvcrt.getch() - - return ch.decode() if sys.version_info.major > 2 else ch.decode(encoding=win_encoding) +# -*- coding: utf-8 -*- +# Initially taken from: +# http://code.activestate.com/recipes/134892/#c9 +# Thanks to Stephen Chappell +import msvcrt +import sys + +win_encoding = "mbcs" + + +XE0_OR_00 = "\x00\xe0" + + +def readchar(blocking=False): + "Get a single character on Windows." + + while msvcrt.kbhit(): + msvcrt.getch() + ch = msvcrt.getch() + # print('ch={}, type(ch)={}'.format(ch, type(ch))) + # while ch.decode(win_encoding) in unicode('\x00\xe0', win_encoding): + while ch.decode(win_encoding) in XE0_OR_00: + # print('found x00 or xe0') + msvcrt.getch() + ch = msvcrt.getch() + + return ch.decode() if sys.version_info.major > 2 else ch.decode(encoding=win_encoding) diff --git a/requirements-test.txt b/requirements-test.txt index 00cce81..462fa01 100644 --- a/requirements-test.txt +++ b/requirements-test.txt @@ -1,4 +1,4 @@ -flake8 -pytest -pytest-cov - +flake8 +pytest +pytest-cov + diff --git a/setup.cfg b/setup.cfg index ba07bfa..c59270b 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,7 +1,7 @@ -[tool:pytest] -norecursedirs = .git venv build dist *egg -addopts = -rfEsxwX --cov readchar - -[flake8] -exclude = **/.*,venv/**,.eggs/** - +[tool:pytest] +norecursedirs = .git venv build dist *egg +addopts = -rfEsxwX --cov readchar + +[flake8] +exclude = **/.*,venv/**,.eggs/** + diff --git a/setup.py b/setup.py index 080a988..e63b3b1 100644 --- a/setup.py +++ b/setup.py @@ -1,87 +1,87 @@ -# -*- coding: utf-8 -*- - -import os -import sys -from io import open - -from setuptools import find_packages, setup -from setuptools.command.test import test as TestCommand - -version = "2.0.1" -github_ref = os.getenv("GITHUB_REF") -if github_ref and github_ref.startswith("refs/tags"): - version = github_ref[10:] - - -def read_description(): - try: - with open("README.rst", encoding="utf8") as fd: - return fd.read() - except: # noqa - return "Error found retrieving description" - - -class PyTest(TestCommand): - user_options = [("pytest-args=", "a", "Arguments to pass to py.test")] - - def initialize_options(self): - TestCommand.initialize_options(self) - self.pytest_args = ["--cov-report=term-missing"] - - def finalize_options(self): - TestCommand.finalize_options(self) - self.test_args = [] - self.test_suite = True - - def run_tests(self): - # import here, cause outside the eggs aren't loaded - import pytest - - errno = pytest.main(self.pytest_args) - sys.exit(errno) - - -setup( - name="readchar", - version=version, - description="Utilities to read single characters and key-strokes", - long_description=read_description(), - classifiers=[ - "Development Status :: 5 - Production/Stable", - "Environment :: Console", - "Intended Audience :: Developers", - "License :: OSI Approved :: MIT License", - "Operating System :: OS Independent", - "Programming Language :: Python :: 2.7", - "Programming Language :: Python :: 3.4", - "Programming Language :: Python :: 3.5", - "Programming Language :: Python :: 3.6", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: Implementation :: CPython", - "Programming Language :: Python :: Implementation :: PyPy", - "Topic :: Software Development", - "Topic :: Software Development :: User Interfaces", - ], - keywords="stdin,command line", - author="Miguel Ángel García", - author_email="miguelangel.garcia@gmail.com", - url="https://github.com/magmax/python-readchar", - license="MIT", - packages=find_packages(exclude=["tests", "venv"]), - include_package_data=True, - zip_safe=False, - cmdclass={"test": PyTest}, - tests_require=[ - "pexpect", - "coverage", - "pytest", - "pytest-cov", - "wheel", - ], - install_requires=[], - setup_requires=[ - "flake8", - ], -) +# -*- coding: utf-8 -*- + +import os +import sys +from io import open + +from setuptools import find_packages, setup +from setuptools.command.test import test as TestCommand + +version = "2.0.1" +github_ref = os.getenv("GITHUB_REF") +if github_ref and github_ref.startswith("refs/tags"): + version = github_ref[10:] + + +def read_description(): + try: + with open("README.rst", encoding="utf8") as fd: + return fd.read() + except: # noqa + return "Error found retrieving description" + + +class PyTest(TestCommand): + user_options = [("pytest-args=", "a", "Arguments to pass to py.test")] + + def initialize_options(self): + TestCommand.initialize_options(self) + self.pytest_args = ["--cov-report=term-missing"] + + def finalize_options(self): + TestCommand.finalize_options(self) + self.test_args = [] + self.test_suite = True + + def run_tests(self): + # import here, cause outside the eggs aren't loaded + import pytest + + errno = pytest.main(self.pytest_args) + sys.exit(errno) + + +setup( + name="readchar", + version=version, + description="Utilities to read single characters and key-strokes", + long_description=read_description(), + classifiers=[ + "Development Status :: 5 - Production/Stable", + "Environment :: Console", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", + "Programming Language :: Python :: 2.7", + "Programming Language :: Python :: 3.4", + "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", + "Topic :: Software Development", + "Topic :: Software Development :: User Interfaces", + ], + keywords="stdin,command line", + author="Miguel Ángel García", + author_email="miguelangel.garcia@gmail.com", + url="https://github.com/magmax/python-readchar", + license="MIT", + packages=find_packages(exclude=["tests", "venv"]), + include_package_data=True, + zip_safe=False, + cmdclass={"test": PyTest}, + tests_require=[ + "pexpect", + "coverage", + "pytest", + "pytest-cov", + "wheel", + ], + install_requires=[], + setup_requires=[ + "flake8", + ], +) diff --git a/test.py b/test.py index 98155e5..d78b18f 100644 --- a/test.py +++ b/test.py @@ -1,39 +1,39 @@ -import readchar.key -import readchar.readchar - -decode_dict = { - readchar.key.ESC: "ESC", - readchar.key.UP: "UP", - readchar.key.DOWN: "DOWN", - readchar.key.LEFT: "LEFT", - readchar.key.RIGHT: "RIGHT", - readchar.key.PAGE_UP: "PAGE_UP", - readchar.key.PAGE_DOWN: "PAGE_DOWN", - readchar.key.HOME: "HOME", - readchar.key.END: "END", - readchar.key.INSERT: "INSERT", - readchar.key.SUPR: "DELETE", - readchar.key.F1: "F1", - readchar.key.F2: "F2", - readchar.key.F3: "F3", - readchar.key.F4: "F4", - readchar.key.F5: "F5", - readchar.key.F6: "F6", - readchar.key.F7: "F7", - readchar.key.F8: "F8", - readchar.key.F9: "F9", - readchar.key.F10: "F10", - readchar.key.F12: "F12", - readchar.key.ALT_A: "ALT_A", -} - -while True: - c = readchar.readkey() - - if c in decode_dict: - print("got {}".format(decode_dict[c])) - else: - print(c) - - if c == "d": - break +import readchar.key +import readchar.readchar + +decode_dict = { + readchar.key.ESC: "ESC", + readchar.key.UP: "UP", + readchar.key.DOWN: "DOWN", + readchar.key.LEFT: "LEFT", + readchar.key.RIGHT: "RIGHT", + readchar.key.PAGE_UP: "PAGE_UP", + readchar.key.PAGE_DOWN: "PAGE_DOWN", + readchar.key.HOME: "HOME", + readchar.key.END: "END", + readchar.key.INSERT: "INSERT", + readchar.key.SUPR: "DELETE", + readchar.key.F1: "F1", + readchar.key.F2: "F2", + readchar.key.F3: "F3", + readchar.key.F4: "F4", + readchar.key.F5: "F5", + readchar.key.F6: "F6", + readchar.key.F7: "F7", + readchar.key.F8: "F8", + readchar.key.F9: "F9", + readchar.key.F10: "F10", + readchar.key.F12: "F12", + readchar.key.ALT_A: "ALT_A", +} + +while True: + c = readchar.readkey() + + if c in decode_dict: + print("got {}".format(decode_dict[c])) + else: + print(c) + + if c == "d": + break From 33998e85f69fc7b1a1186b50bf6c3862285b03f3 Mon Sep 17 00:00:00 2001 From: root Date: Tue, 13 Jul 2021 09:39:05 +0200 Subject: [PATCH 3/4] dos2linux --- .coveragerc | 4 +- .flake8 | 4 +- .github/workflows/python-publish.yml | 62 +++++++-------- .github/workflows/python-test.yml | 88 +++++++++++----------- .gitignore | 26 +++---- .pre-commit-config.yaml | 34 ++++----- .travis.yml | 72 +++++++++--------- tests/unit/test_key.py | 34 ++++----- tests/unit/test_readkey.py | 108 +++++++++++++-------------- 9 files changed, 216 insertions(+), 216 deletions(-) diff --git a/.coveragerc b/.coveragerc index e448012..e7d592e 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1,2 +1,2 @@ -[run] -omit = */tests* +[run] +omit = */tests* diff --git a/.flake8 b/.flake8 index be6e8fa..c057b0f 100644 --- a/.flake8 +++ b/.flake8 @@ -1,2 +1,2 @@ -[flake8] -max-line-length=119 +[flake8] +max-line-length=119 diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index cad3475..affc6a5 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -1,31 +1,31 @@ -# This workflow will upload a Python Package using Twine when a release is created -# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries - -name: Upload Python Package - -on: - release: - types: [created] - -jobs: - deploy: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - name: Set up Python - uses: actions/setup-python@v2 - with: - python-version: '3.x' - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install setuptools wheel twine - - name: Build and publish - env: - TWINE_USERNAME: __token__ - TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }} - run: | - python setup.py sdist bdist_wheel - twine upload dist/* +# This workflow will upload a Python Package using Twine when a release is created +# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries + +name: Upload Python Package + +on: + release: + types: [created] + +jobs: + deploy: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: '3.x' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install setuptools wheel twine + - name: Build and publish + env: + TWINE_USERNAME: __token__ + TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }} + run: | + python setup.py sdist bdist_wheel + twine upload dist/* diff --git a/.github/workflows/python-test.yml b/.github/workflows/python-test.yml index d4f1060..1996d19 100644 --- a/.github/workflows/python-test.yml +++ b/.github/workflows/python-test.yml @@ -1,44 +1,44 @@ -# This workflow will install Python dependencies, run tests and lint with a variety of Python versions -# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions - -name: Python package - -on: - push: - branches: [ master ] - pull_request: - branches: [ master ] - -jobs: - build: - - runs-on: ubuntu-latest - strategy: - matrix: - python-version: - - "2.7" - - "3.5" - - "3.6" - - "3.7" - - "3.8" - - "3.9" - - steps: - - uses: actions/checkout@v2 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - python -m pip install --upgrade pip - python -m pip install -r requirements-test.txt - - name: Lint with flake8 - run: | - # stop the build if there are Python syntax errors or undefined names - flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics - # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics - - name: Test with pytest - run: | - pytest +# This workflow will install Python dependencies, run tests and lint with a variety of Python versions +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions + +name: Python package + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build: + + runs-on: ubuntu-latest + strategy: + matrix: + python-version: + - "2.7" + - "3.5" + - "3.6" + - "3.7" + - "3.8" + - "3.9" + + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + python -m pip install -r requirements-test.txt + - name: Lint with flake8 + run: | + # stop the build if there are Python syntax errors or undefined names + flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics + # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide + flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + - name: Test with pytest + run: | + pytest diff --git a/.gitignore b/.gitignore index c8d4237..9b44a48 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,13 @@ -*~ -\#* -\.\#* -*.pyc -*.egg-info/ -build/ -dist/ -venv/ -.coverage -coverage.xml -.eggs -*.egg -.idea/ +*~ +\#* +\.\#* +*.pyc +*.egg-info/ +build/ +dist/ +venv/ +.coverage +coverage.xml +.eggs +*.egg +.idea/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f444074..5399570 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,17 +1,17 @@ -repos: - - repo: https://github.com/PyCQA/isort.git - rev: 5.7.0 - hooks: - - id: isort - - repo: https://github.com/psf/black - rev: 20.8b1 - hooks: - - id: black - language_version: python3 - args: - - -l - - "119" - - repo: https://gitlab.com/pycqa/flake8 - rev: 6de8252c035844f1e679f509b5f37340b44d5c39 - hooks: - - id: flake8 +repos: + - repo: https://github.com/PyCQA/isort.git + rev: 5.7.0 + hooks: + - id: isort + - repo: https://github.com/psf/black + rev: 20.8b1 + hooks: + - id: black + language_version: python3 + args: + - -l + - "119" + - repo: https://gitlab.com/pycqa/flake8 + rev: 6de8252c035844f1e679f509b5f37340b44d5c39 + hooks: + - id: flake8 diff --git a/.travis.yml b/.travis.yml index bd88a0a..5a93ab2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,36 +1,36 @@ -language: python - -sudo: false - -python: - - "2.7" - - "3.4" - - "3.5" - - "3.6" - - "3.7-dev" - - "pypy" - - "pypy3" - -matrix: - include: - - python: "3.6" - env: TMODE=flake8 -env: - TMODE=test - -install: - - "if [[ $TMODE == 'test' ]]; then pip install pytest; fi" - - "if [[ $TMODE == 'test' ]]; then python setup.py install; fi" - - pip freeze --all - - ls -lh .eggs || true - -script: - - python setup.py $TMODE - -after_success: - - "if [[ $TMODE == 'test' ]]; then pip install python-coveralls; coveralls; fi" - -notifications: - email: - on_success: change - on_failure: change +language: python + +sudo: false + +python: + - "2.7" + - "3.4" + - "3.5" + - "3.6" + - "3.7-dev" + - "pypy" + - "pypy3" + +matrix: + include: + - python: "3.6" + env: TMODE=flake8 +env: + TMODE=test + +install: + - "if [[ $TMODE == 'test' ]]; then pip install pytest; fi" + - "if [[ $TMODE == 'test' ]]; then python setup.py install; fi" + - pip freeze --all + - ls -lh .eggs || true + +script: + - python setup.py $TMODE + +after_success: + - "if [[ $TMODE == 'test' ]]; then pip install python-coveralls; coveralls; fi" + +notifications: + email: + on_success: change + on_failure: change diff --git a/tests/unit/test_key.py b/tests/unit/test_key.py index e669e6a..ef605f3 100644 --- a/tests/unit/test_key.py +++ b/tests/unit/test_key.py @@ -1,17 +1,17 @@ -import unittest - -from readchar import key - - -class KeyTest(unittest.TestCase): - def test_character_length_1(self): - self.assertEqual(1, len(key.CTRL_A)) - - def test_character_length_2(self): - self.assertEqual(2, len(key.ALT_A)) - - def test_character_length_3(self): - self.assertEqual(3, len(key.UP)) - - def test_character_length_4(self): - self.assertEqual(4, len(key.CTRL_ALT_SUPR)) +import unittest + +from readchar import key + + +class KeyTest(unittest.TestCase): + def test_character_length_1(self): + self.assertEqual(1, len(key.CTRL_A)) + + def test_character_length_2(self): + self.assertEqual(2, len(key.ALT_A)) + + def test_character_length_3(self): + self.assertEqual(3, len(key.UP)) + + def test_character_length_4(self): + self.assertEqual(4, len(key.CTRL_ALT_SUPR)) diff --git a/tests/unit/test_readkey.py b/tests/unit/test_readkey.py index d8968f3..5f52727 100644 --- a/tests/unit/test_readkey.py +++ b/tests/unit/test_readkey.py @@ -1,54 +1,54 @@ -import unittest - -from readchar import readkey - - -def readchar_fn_factory(stream): - - v = [x for x in stream] - - def inner(): - return v.pop(0) - - return inner - - -class ReadKeyTest(unittest.TestCase): - def test_basic_character(self): - getchar_fn = readchar_fn_factory("a") - - result = readkey(getchar_fn) - - self.assertEqual("a", result) - - def test_string_instead_of_char(self): - char = "a" - getchar_fn = readchar_fn_factory(char + "bcde") - - result = readkey(getchar_fn) - - self.assertEqual(char, result) - - def test_special_combo_character(self): - char = "\x1b\x01" - getchar_fn = readchar_fn_factory(char + "foo") - - result = readkey(getchar_fn) - - self.assertEqual(char, result) - - def test_special_key(self): - char = "\x1b\x5b\x41" - getchar_fn = readchar_fn_factory(char + "foo") - - result = readkey(getchar_fn) - - self.assertEqual(char, result) - - def test_special_key_combo(self): - char = "\x1b\x5b\x33\x5e" - getchar_fn = readchar_fn_factory(char + "foo") - - result = readkey(getchar_fn) - - self.assertEqual(char, result) +import unittest + +from readchar import readkey + + +def readchar_fn_factory(stream): + + v = [x for x in stream] + + def inner(): + return v.pop(0) + + return inner + + +class ReadKeyTest(unittest.TestCase): + def test_basic_character(self): + getchar_fn = readchar_fn_factory("a") + + result = readkey(getchar_fn) + + self.assertEqual("a", result) + + def test_string_instead_of_char(self): + char = "a" + getchar_fn = readchar_fn_factory(char + "bcde") + + result = readkey(getchar_fn) + + self.assertEqual(char, result) + + def test_special_combo_character(self): + char = "\x1b\x01" + getchar_fn = readchar_fn_factory(char + "foo") + + result = readkey(getchar_fn) + + self.assertEqual(char, result) + + def test_special_key(self): + char = "\x1b\x5b\x41" + getchar_fn = readchar_fn_factory(char + "foo") + + result = readkey(getchar_fn) + + self.assertEqual(char, result) + + def test_special_key_combo(self): + char = "\x1b\x5b\x33\x5e" + getchar_fn = readchar_fn_factory(char + "foo") + + result = readkey(getchar_fn) + + self.assertEqual(char, result) From aa1e80432d96ca28eaf089afb822593508c186fe Mon Sep 17 00:00:00 2001 From: root Date: Tue, 13 Jul 2021 09:56:43 +0200 Subject: [PATCH 4/4] unix2dos --- readchar/readchar.py | 194 +++++++++++++++++------------------ readchar/readchar_windows.py | 54 +++++----- 2 files changed, 124 insertions(+), 124 deletions(-) diff --git a/readchar/readchar.py b/readchar/readchar.py index 652d6b9..fc35429 100644 --- a/readchar/readchar.py +++ b/readchar/readchar.py @@ -1,97 +1,97 @@ -# -*- coding: utf-8 -*- -# This file is based on this gist: -# http://code.activestate.com/recipes/134892/ -# So real authors are DannyYoo and company. -import sys - -if sys.platform.startswith("linux"): - from .readchar_linux import readchar -elif sys.platform == "darwin": - from .readchar_linux import readchar -elif sys.platform in ("win32", "cygwin"): - import msvcrt - - from . import key - from .readchar_windows import readchar -else: - raise NotImplementedError("The platform %s is not supported yet" % sys.platform) - - -if sys.platform in ("win32", "cygwin"): - # - # Windows uses scan codes for extended characters. The ordinal returned is - # 256 * the scan code. This dictionary translates scan codes to the - # unicode sequences expected by readkey. - # - # for windows scan codes see: - # https://msdn.microsoft.com/en-us/library/aa299374 - # or - # http://www.quadibloc.com/comp/scan.htm - xlate_dict = { - 13: key.ENTER, - 27: key.ESC, - 15104: key.F1, - 15360: key.F2, - 15616: key.F3, - 15872: key.F4, - 16128: key.F5, - 16384: key.F6, - 16640: key.F7, - 16896: key.F8, - 17152: key.F9, - 17408: key.F10, - 22272: key.F11, - 34528: key.F12, - 7680: key.ALT_A, - # don't have table entries for... - # CTRL_ALT_A, # Ctrl-Alt-A, etc. - # CTRL_ALT_SUPR, - # CTRL-F1 - 21216: key.INSERT, - 21472: key.SUPR, # key.py uses SUPR, not DELETE - 18912: key.PAGE_UP, - 20960: key.PAGE_DOWN, - 18400: key.HOME, - 20448: key.END, - 18656: key.UP, - 20704: key.DOWN, - 19424: key.LEFT, - 19936: key.RIGHT, - } - - def readkey(getchar_fn=None): - # Get a single character on Windows. if an extended key is pressed, the - # Windows scan code is translated into a the unicode sequences readchar - # expects (see key.py). - while True: - if msvcrt.kbhit(): - ch = msvcrt.getch() - a = ord(ch) - if a == 0 or a == 224: - b = ord(msvcrt.getch()) - x = a + (b * 256) - - try: - return xlate_dict[x] - except KeyError: - return None - return x - else: - return ch.decode() - - -else: - - def readkey(getchar_fn=None): - getchar = getchar_fn or readchar - c1 = getchar() - if ord(c1) != 0x1B: - return c1 - c2 = getchar() - if ord(c2) != 0x5B: - return c1 + c2 - c3 = getchar() - if ord(c3) != 0x33: - return c1 + c2 + c3 - c4 = getchar() - return c1 + c2 + c3 + c4 +# -*- coding: utf-8 -*- +# This file is based on this gist: +# http://code.activestate.com/recipes/134892/ +# So real authors are DannyYoo and company. +import sys + +if sys.platform.startswith("linux"): + from .readchar_linux import readchar +elif sys.platform == "darwin": + from .readchar_linux import readchar +elif sys.platform in ("win32", "cygwin"): + import msvcrt + + from . import key + from .readchar_windows import readchar +else: + raise NotImplementedError("The platform %s is not supported yet" % sys.platform) + + +if sys.platform in ("win32", "cygwin"): + # + # Windows uses scan codes for extended characters. The ordinal returned is + # 256 * the scan code. This dictionary translates scan codes to the + # unicode sequences expected by readkey. + # + # for windows scan codes see: + # https://msdn.microsoft.com/en-us/library/aa299374 + # or + # http://www.quadibloc.com/comp/scan.htm + xlate_dict = { + 13: key.ENTER, + 27: key.ESC, + 15104: key.F1, + 15360: key.F2, + 15616: key.F3, + 15872: key.F4, + 16128: key.F5, + 16384: key.F6, + 16640: key.F7, + 16896: key.F8, + 17152: key.F9, + 17408: key.F10, + 22272: key.F11, + 34528: key.F12, + 7680: key.ALT_A, + # don't have table entries for... + # CTRL_ALT_A, # Ctrl-Alt-A, etc. + # CTRL_ALT_SUPR, + # CTRL-F1 + 21216: key.INSERT, + 21472: key.SUPR, # key.py uses SUPR, not DELETE + 18912: key.PAGE_UP, + 20960: key.PAGE_DOWN, + 18400: key.HOME, + 20448: key.END, + 18656: key.UP, + 20704: key.DOWN, + 19424: key.LEFT, + 19936: key.RIGHT, + } + + def readkey(getchar_fn=None): + # Get a single character on Windows. if an extended key is pressed, the + # Windows scan code is translated into a the unicode sequences readchar + # expects (see key.py). + while True: + if msvcrt.kbhit(): + ch = msvcrt.getch() + a = ord(ch) + if a == 0 or a == 224: + b = ord(msvcrt.getch()) + x = a + (b * 256) + + try: + return xlate_dict[x] + except KeyError: + return None + return x + else: + return ch.decode() + + +else: + + def readkey(getchar_fn=None): + getchar = getchar_fn or readchar + c1 = getchar() + if ord(c1) != 0x1B: + return c1 + c2 = getchar() + if ord(c2) != 0x5B: + return c1 + c2 + c3 = getchar() + if ord(c3) != 0x33: + return c1 + c2 + c3 + c4 = getchar() + return c1 + c2 + c3 + c4 diff --git a/readchar/readchar_windows.py b/readchar/readchar_windows.py index 04de626..c197a9a 100644 --- a/readchar/readchar_windows.py +++ b/readchar/readchar_windows.py @@ -1,27 +1,27 @@ -# -*- coding: utf-8 -*- -# Initially taken from: -# http://code.activestate.com/recipes/134892/#c9 -# Thanks to Stephen Chappell -import msvcrt -import sys - -win_encoding = "mbcs" - - -XE0_OR_00 = "\x00\xe0" - - -def readchar(blocking=False): - "Get a single character on Windows." - - while msvcrt.kbhit(): - msvcrt.getch() - ch = msvcrt.getch() - # print('ch={}, type(ch)={}'.format(ch, type(ch))) - # while ch.decode(win_encoding) in unicode('\x00\xe0', win_encoding): - while ch.decode(win_encoding) in XE0_OR_00: - # print('found x00 or xe0') - msvcrt.getch() - ch = msvcrt.getch() - - return ch.decode() if sys.version_info.major > 2 else ch.decode(encoding=win_encoding) +# -*- coding: utf-8 -*- +# Initially taken from: +# http://code.activestate.com/recipes/134892/#c9 +# Thanks to Stephen Chappell +import msvcrt +import sys + +win_encoding = "mbcs" + + +XE0_OR_00 = "\x00\xe0" + + +def readchar(blocking=False): + "Get a single character on Windows." + + while msvcrt.kbhit(): + msvcrt.getch() + ch = msvcrt.getch() + # print('ch={}, type(ch)={}'.format(ch, type(ch))) + # while ch.decode(win_encoding) in unicode('\x00\xe0', win_encoding): + while ch.decode(win_encoding) in XE0_OR_00: + # print('found x00 or xe0') + msvcrt.getch() + ch = msvcrt.getch() + + return ch.decode() if sys.version_info.major > 2 else ch.decode(encoding=win_encoding)