Commit fa3422e5 by mihkevich

Make env and start by keyup home from key_listener.py

parent 533b95f6
<#
.Synopsis
Activate a Python virtual environment for the current PowerShell session.
.Description
Pushes the python executable for a virtual environment to the front of the
$Env:PATH environment variable and sets the prompt to signify that you are
in a Python virtual environment. Makes use of the command line switches as
well as the `pyvenv.cfg` file values present in the virtual environment.
.Parameter VenvDir
Path to the directory that contains the virtual environment to activate. The
default value for this is the parent of the directory that the Activate.ps1
script is located within.
.Parameter Prompt
The prompt prefix to display when this virtual environment is activated. By
default, this prompt is the name of the virtual environment folder (VenvDir)
surrounded by parentheses and followed by a single space (ie. '(.venv) ').
.Example
Activate.ps1
Activates the Python virtual environment that contains the Activate.ps1 script.
.Example
Activate.ps1 -Verbose
Activates the Python virtual environment that contains the Activate.ps1 script,
and shows extra information about the activation as it executes.
.Example
Activate.ps1 -VenvDir C:\Users\MyUser\Common\.venv
Activates the Python virtual environment located in the specified location.
.Example
Activate.ps1 -Prompt "MyPython"
Activates the Python virtual environment that contains the Activate.ps1 script,
and prefixes the current prompt with the specified string (surrounded in
parentheses) while the virtual environment is active.
.Notes
On Windows, it may be required to enable this Activate.ps1 script by setting the
execution policy for the user. You can do this by issuing the following PowerShell
command:
PS C:\> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
For more information on Execution Policies:
https://go.microsoft.com/fwlink/?LinkID=135170
#>
Param(
[Parameter(Mandatory = $false)]
[String]
$VenvDir,
[Parameter(Mandatory = $false)]
[String]
$Prompt
)
<# Function declarations --------------------------------------------------- #>
<#
.Synopsis
Remove all shell session elements added by the Activate script, including the
addition of the virtual environment's Python executable from the beginning of
the PATH variable.
.Parameter NonDestructive
If present, do not remove this function from the global namespace for the
session.
#>
function global:deactivate ([switch]$NonDestructive) {
# Revert to original values
# The prior prompt:
if (Test-Path -Path Function:_OLD_VIRTUAL_PROMPT) {
Copy-Item -Path Function:_OLD_VIRTUAL_PROMPT -Destination Function:prompt
Remove-Item -Path Function:_OLD_VIRTUAL_PROMPT
}
# The prior PYTHONHOME:
if (Test-Path -Path Env:_OLD_VIRTUAL_PYTHONHOME) {
Copy-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME -Destination Env:PYTHONHOME
Remove-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME
}
# The prior PATH:
if (Test-Path -Path Env:_OLD_VIRTUAL_PATH) {
Copy-Item -Path Env:_OLD_VIRTUAL_PATH -Destination Env:PATH
Remove-Item -Path Env:_OLD_VIRTUAL_PATH
}
# Just remove the VIRTUAL_ENV altogether:
if (Test-Path -Path Env:VIRTUAL_ENV) {
Remove-Item -Path env:VIRTUAL_ENV
}
# Just remove the _PYTHON_VENV_PROMPT_PREFIX altogether:
if (Get-Variable -Name "_PYTHON_VENV_PROMPT_PREFIX" -ErrorAction SilentlyContinue) {
Remove-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Scope Global -Force
}
# Leave deactivate function in the global namespace if requested:
if (-not $NonDestructive) {
Remove-Item -Path function:deactivate
}
}
<#
.Description
Get-PyVenvConfig parses the values from the pyvenv.cfg file located in the
given folder, and returns them in a map.
For each line in the pyvenv.cfg file, if that line can be parsed into exactly
two strings separated by `=` (with any amount of whitespace surrounding the =)
then it is considered a `key = value` line. The left hand string is the key,
the right hand is the value.
If the value starts with a `'` or a `"` then the first and last character is
stripped from the value before being captured.
.Parameter ConfigDir
Path to the directory that contains the `pyvenv.cfg` file.
#>
function Get-PyVenvConfig(
[String]
$ConfigDir
) {
Write-Verbose "Given ConfigDir=$ConfigDir, obtain values in pyvenv.cfg"
# Ensure the file exists, and issue a warning if it doesn't (but still allow the function to continue).
$pyvenvConfigPath = Join-Path -Resolve -Path $ConfigDir -ChildPath 'pyvenv.cfg' -ErrorAction Continue
# An empty map will be returned if no config file is found.
$pyvenvConfig = @{ }
if ($pyvenvConfigPath) {
Write-Verbose "File exists, parse `key = value` lines"
$pyvenvConfigContent = Get-Content -Path $pyvenvConfigPath
$pyvenvConfigContent | ForEach-Object {
$keyval = $PSItem -split "\s*=\s*", 2
if ($keyval[0] -and $keyval[1]) {
$val = $keyval[1]
# Remove extraneous quotations around a string value.
if ("'""".Contains($val.Substring(0, 1))) {
$val = $val.Substring(1, $val.Length - 2)
}
$pyvenvConfig[$keyval[0]] = $val
Write-Verbose "Adding Key: '$($keyval[0])'='$val'"
}
}
}
return $pyvenvConfig
}
<# Begin Activate script --------------------------------------------------- #>
# Determine the containing directory of this script
$VenvExecPath = Split-Path -Parent $MyInvocation.MyCommand.Definition
$VenvExecDir = Get-Item -Path $VenvExecPath
Write-Verbose "Activation script is located in path: '$VenvExecPath'"
Write-Verbose "VenvExecDir Fullname: '$($VenvExecDir.FullName)"
Write-Verbose "VenvExecDir Name: '$($VenvExecDir.Name)"
# Set values required in priority: CmdLine, ConfigFile, Default
# First, get the location of the virtual environment, it might not be
# VenvExecDir if specified on the command line.
if ($VenvDir) {
Write-Verbose "VenvDir given as parameter, using '$VenvDir' to determine values"
}
else {
Write-Verbose "VenvDir not given as a parameter, using parent directory name as VenvDir."
$VenvDir = $VenvExecDir.Parent.FullName.TrimEnd("\\/")
Write-Verbose "VenvDir=$VenvDir"
}
# Next, read the `pyvenv.cfg` file to determine any required value such
# as `prompt`.
$pyvenvCfg = Get-PyVenvConfig -ConfigDir $VenvDir
# Next, set the prompt from the command line, or the config file, or
# just use the name of the virtual environment folder.
if ($Prompt) {
Write-Verbose "Prompt specified as argument, using '$Prompt'"
}
else {
Write-Verbose "Prompt not specified as argument to script, checking pyvenv.cfg value"
if ($pyvenvCfg -and $pyvenvCfg['prompt']) {
Write-Verbose " Setting based on value in pyvenv.cfg='$($pyvenvCfg['prompt'])'"
$Prompt = $pyvenvCfg['prompt'];
}
else {
Write-Verbose " Setting prompt based on parent's directory's name. (Is the directory name passed to venv module when creating the virutal environment)"
Write-Verbose " Got leaf-name of $VenvDir='$(Split-Path -Path $venvDir -Leaf)'"
$Prompt = Split-Path -Path $venvDir -Leaf
}
}
Write-Verbose "Prompt = '$Prompt'"
Write-Verbose "VenvDir='$VenvDir'"
# Deactivate any currently active virtual environment, but leave the
# deactivate function in place.
deactivate -nondestructive
# Now set the environment variable VIRTUAL_ENV, used by many tools to determine
# that there is an activated venv.
$env:VIRTUAL_ENV = $VenvDir
if (-not $Env:VIRTUAL_ENV_DISABLE_PROMPT) {
Write-Verbose "Setting prompt to '$Prompt'"
# Set the prompt to include the env name
# Make sure _OLD_VIRTUAL_PROMPT is global
function global:_OLD_VIRTUAL_PROMPT { "" }
Copy-Item -Path function:prompt -Destination function:_OLD_VIRTUAL_PROMPT
New-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Description "Python virtual environment prompt prefix" -Scope Global -Option ReadOnly -Visibility Public -Value $Prompt
function global:prompt {
Write-Host -NoNewline -ForegroundColor Green "($_PYTHON_VENV_PROMPT_PREFIX) "
_OLD_VIRTUAL_PROMPT
}
}
# Clear PYTHONHOME
if (Test-Path -Path Env:PYTHONHOME) {
Copy-Item -Path Env:PYTHONHOME -Destination Env:_OLD_VIRTUAL_PYTHONHOME
Remove-Item -Path Env:PYTHONHOME
}
# Add the venv to the PATH
Copy-Item -Path Env:PATH -Destination Env:_OLD_VIRTUAL_PATH
$Env:PATH = "$VenvExecDir$([System.IO.Path]::PathSeparator)$Env:PATH"
# This file must be used with "source bin/activate" *from bash*
# you cannot run it directly
deactivate () {
# reset old environment variables
if [ -n "${_OLD_VIRTUAL_PATH:-}" ] ; then
PATH="${_OLD_VIRTUAL_PATH:-}"
export PATH
unset _OLD_VIRTUAL_PATH
fi
if [ -n "${_OLD_VIRTUAL_PYTHONHOME:-}" ] ; then
PYTHONHOME="${_OLD_VIRTUAL_PYTHONHOME:-}"
export PYTHONHOME
unset _OLD_VIRTUAL_PYTHONHOME
fi
# This should detect bash and zsh, which have a hash command that must
# be called to get it to forget past commands. Without forgetting
# past commands the $PATH changes we made may not be respected
if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then
hash -r 2> /dev/null
fi
if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then
PS1="${_OLD_VIRTUAL_PS1:-}"
export PS1
unset _OLD_VIRTUAL_PS1
fi
unset VIRTUAL_ENV
if [ ! "${1:-}" = "nondestructive" ] ; then
# Self destruct!
unset -f deactivate
fi
}
# unset irrelevant variables
deactivate nondestructive
VIRTUAL_ENV="/home/user/dev/easy-media-controller/env"
export VIRTUAL_ENV
_OLD_VIRTUAL_PATH="$PATH"
PATH="$VIRTUAL_ENV/bin:$PATH"
export PATH
# unset PYTHONHOME if set
# this will fail if PYTHONHOME is set to the empty string (which is bad anyway)
# could use `if (set -u; : $PYTHONHOME) ;` in bash
if [ -n "${PYTHONHOME:-}" ] ; then
_OLD_VIRTUAL_PYTHONHOME="${PYTHONHOME:-}"
unset PYTHONHOME
fi
if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then
_OLD_VIRTUAL_PS1="${PS1:-}"
PS1="(env) ${PS1:-}"
export PS1
fi
# This should detect bash and zsh, which have a hash command that must
# be called to get it to forget past commands. Without forgetting
# past commands the $PATH changes we made may not be respected
if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then
hash -r 2> /dev/null
fi
# This file must be used with "source bin/activate.csh" *from csh*.
# You cannot run it directly.
# Created by Davide Di Blasi <davidedb@gmail.com>.
# Ported to Python 3.3 venv by Andrew Svetlov <andrew.svetlov@gmail.com>
alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; test "\!:*" != "nondestructive" && unalias deactivate'
# Unset irrelevant variables.
deactivate nondestructive
setenv VIRTUAL_ENV "/home/user/dev/easy-media-controller/env"
set _OLD_VIRTUAL_PATH="$PATH"
setenv PATH "$VIRTUAL_ENV/bin:$PATH"
set _OLD_VIRTUAL_PROMPT="$prompt"
if (! "$?VIRTUAL_ENV_DISABLE_PROMPT") then
set prompt = "(env) $prompt"
endif
alias pydoc python -m pydoc
rehash
# This file must be used with "source <venv>/bin/activate.fish" *from fish*
# (https://fishshell.com/); you cannot run it directly.
function deactivate -d "Exit virtual environment and return to normal shell environment"
# reset old environment variables
if test -n "$_OLD_VIRTUAL_PATH"
set -gx PATH $_OLD_VIRTUAL_PATH
set -e _OLD_VIRTUAL_PATH
end
if test -n "$_OLD_VIRTUAL_PYTHONHOME"
set -gx PYTHONHOME $_OLD_VIRTUAL_PYTHONHOME
set -e _OLD_VIRTUAL_PYTHONHOME
end
if test -n "$_OLD_FISH_PROMPT_OVERRIDE"
functions -e fish_prompt
set -e _OLD_FISH_PROMPT_OVERRIDE
functions -c _old_fish_prompt fish_prompt
functions -e _old_fish_prompt
end
set -e VIRTUAL_ENV
if test "$argv[1]" != "nondestructive"
# Self-destruct!
functions -e deactivate
end
end
# Unset irrelevant variables.
deactivate nondestructive
set -gx VIRTUAL_ENV "/home/user/dev/easy-media-controller/env"
set -gx _OLD_VIRTUAL_PATH $PATH
set -gx PATH "$VIRTUAL_ENV/bin" $PATH
# Unset PYTHONHOME if set.
if set -q PYTHONHOME
set -gx _OLD_VIRTUAL_PYTHONHOME $PYTHONHOME
set -e PYTHONHOME
end
if test -z "$VIRTUAL_ENV_DISABLE_PROMPT"
# fish uses a function instead of an env var to generate the prompt.
# Save the current fish_prompt function as the function _old_fish_prompt.
functions -c fish_prompt _old_fish_prompt
# With the original prompt function renamed, we can override with our own.
function fish_prompt
# Save the return status of the last command.
set -l old_status $status
# Output the venv prompt; color taken from the blue of the Python logo.
printf "%s%s%s" (set_color 4B8BBE) "(env) " (set_color normal)
# Restore the return status of the previous command.
echo "exit $old_status" | .
# Output the original/"old" prompt.
_old_fish_prompt
end
set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV"
end
#!/home/user/dev/easy-media-controller/env/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from setuptools.command.easy_install import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())
#!/home/user/dev/easy-media-controller/env/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from setuptools.command.easy_install import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())
#!/home/user/dev/easy-media-controller/env/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from pip._internal.cli.main import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())
#!/home/user/dev/easy-media-controller/env/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from pip._internal.cli.main import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())
#!/home/user/dev/easy-media-controller/env/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from pip._internal.cli.main import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())
python3
\ No newline at end of file
/usr/bin/python3
\ No newline at end of file
python3
\ No newline at end of file
"""Run the EasyInstall command"""
if __name__ == '__main__':
from setuptools.command.easy_install import main
main()
The authors in alphabetical order
* Charlie Clark
* Elias Rabel
\ No newline at end of file
This software is under the MIT Licence
======================================
Copyright (c) 2010 openpyxl
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Odict implementation in openpyxl/writer/odict.py uses the following licence:
Copyright (c) 2001-2011 Python Software Foundation
2011 Raymond Hettinger
License: PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
See http://www.opensource.org/licenses/Python-2.0 for full terms
Note: backport changes by Raymond were originally distributed under MIT
license, but since the original license for Python is more
restrictive than MIT, code cannot be released under its terms and
still adheres to the limitations of Python license.
Metadata-Version: 2.1
Name: et-xmlfile
Version: 1.1.0
Summary: An implementation of lxml.xmlfile for the standard library
Home-page: https://foss.heptapod.net/openpyxl/et_xmlfile
Author: See ATUHORS.txt
Author-email: charlie.clark@clark-consulting.eu
License: MIT
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Operating System :: MacOS :: MacOS X
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: POSIX
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Requires-Python: >=3.6
et_xmfile
=========
et_xmlfile is a low memory library for creating large XML files.
It is based upon the `xmlfile module from lxml <http://lxml.de/api.html#incremental-xml-generation>`_ with the aim of allowing code to be developed that will work with both libraries. It was developed initially for the openpyxl project but is now a standalone module.
The code was written by Elias Rabel as part of the `Python Düsseldorf <http://pyddf.de>`_ openpyxl sprint in September 2014.
Note on performance
-------------------
The code was not developed with performance in mind but turned out to be faster than the existing SAX-based implementation but is significantly slower than lxml's xmlfile. There is one area where an optimisation for lxml will negatively affect the performance of et_xmfile and that is when using the `.element()` method on an xmlfile context manager. It is, therefore, recommended not to use this, though the method is provided for code compatibility.
et_xmlfile-1.1.0.dist-info/AUTHORS.txt,sha256=Y6mQLe0ywXMVP7WVFrZgEW3CqhIv-plM1CaOtdtBuXs,64
et_xmlfile-1.1.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
et_xmlfile-1.1.0.dist-info/LICENCE.rst,sha256=r-YrNgzcqB-43m7kt2ENodhsORd3qAx6y20RRVxTxCk,1694
et_xmlfile-1.1.0.dist-info/METADATA,sha256=B5hV5UW4GqmWGgwAW44C2ofZZEmV0MRnTEU98kzcUGw,1775
et_xmlfile-1.1.0.dist-info/RECORD,,
et_xmlfile-1.1.0.dist-info/WHEEL,sha256=OqRkF0eY5GHssMorFjlbTIq072vpHpF60fIQA6lS9xA,92
et_xmlfile-1.1.0.dist-info/top_level.txt,sha256=34-74d5NNARgTsPxCMta5o28XpBNmSN0iCZhtmx2Fk8,11
et_xmlfile/__init__.py,sha256=-oTKwE6upIG2gOmnOc4KLgV-pKbBwy-zhQfizbmCruQ,269
et_xmlfile/__pycache__/__init__.cpython-39.pyc,,
et_xmlfile/__pycache__/xmlfile.cpython-39.pyc,,
et_xmlfile/xmlfile.py,sha256=_h20RRb3ptDZ6xXoxMU_Wrx8rG6UZsg0TS7HEOrotzg,3204
Wheel-Version: 1.0
Generator: bdist_wheel (0.36.2)
Root-Is-Purelib: true
Tag: py3-none-any
from __future__ import absolute_import
from .xmlfile import xmlfile
# constants
__version__ = '1.1.0'
__author__ = 'See ATUHORS.txt'
__license__ = 'MIT'
__author_email__ = 'charlie.clark@clark-consulting.eu'
__url__ = 'https://foss.heptapod.net/openpyxl/et_xmlfile'
from __future__ import absolute_import
# Copyright (c) 2010-2015 openpyxl
"""Implements the lxml.etree.xmlfile API using the standard library xml.etree"""
from contextlib import contextmanager
from xml.etree.ElementTree import Element, tostring
class LxmlSyntaxError(Exception):
pass
class _FakeIncrementalFileWriter(object):
"""Replacement for _IncrementalFileWriter of lxml.
Uses ElementTree to build xml in memory."""
def __init__(self, output_file):
self._element_stack = []
self._top_element = None
self._file = output_file
self._have_root = False
@contextmanager
def element(self, tag, attrib=None, nsmap=None, **_extra):
"""Create a new xml element using a context manager.
The elements are written when the top level context is left.
This is for code compatibility only as it is quite slow.
"""
# __enter__ part
self._have_root = True
if attrib is None:
attrib = {}
self._top_element = Element(tag, attrib=attrib, **_extra)
self._top_element.text = ''
self._top_element.tail = ''
self._element_stack.append(self._top_element)
yield
# __exit__ part
el = self._element_stack.pop()
if self._element_stack:
parent = self._element_stack[-1]
parent.append(self._top_element)
self._top_element = parent
else:
self._write_element(el)
self._top_element = None
def write(self, arg):
"""Write a string or subelement."""
if isinstance(arg, str):
# it is not allowed to write a string outside of an element
if self._top_element is None:
raise LxmlSyntaxError()
if len(self._top_element) == 0:
# element has no children: add string to text
self._top_element.text += arg
else:
# element has children: add string to tail of last child
self._top_element[-1].tail += arg
else:
if self._top_element is not None:
self._top_element.append(arg)
elif not self._have_root:
self._write_element(arg)
else:
raise LxmlSyntaxError()
def _write_element(self, element):
xml = tostring(element)
self._file.write(xml)
def __enter__(self):
pass
def __exit__(self, type, value, traceback):
# without root the xml document is incomplete
if not self._have_root:
raise LxmlSyntaxError()
class xmlfile(object):
"""Context manager that can replace lxml.etree.xmlfile."""
def __init__(self, output_file, buffered=False, encoding=None, close=False):
if isinstance(output_file, str):
self._file = open(output_file, 'wb')
self._close = True
else:
self._file = output_file
self._close = close
def __enter__(self):
return _FakeIncrementalFileWriter(self._file)
def __exit__(self, type, value, traceback):
if self._close == True:
self._file.close()
Copyright (c) 2012-2016 Georgi Valkov. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. 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.
3. Neither the name of author 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 AUTHORS OR
COPYRIGHT HOLDERS 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.
Metadata-Version: 2.1
Name: evdev
Version: 1.4.0
Summary: Bindings to the Linux input handling subsystem
Home-page: https://github.com/gvalkov/python-evdev
Author: Georgi Valkov
Author-email: georgi.t.valkov@gmail.com
License: Revised BSD License
Keywords: evdev input uinput
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.3
Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Operating System :: POSIX :: Linux
Classifier: Intended Audience :: Developers
Classifier: Topic :: Software Development :: Libraries
Classifier: License :: OSI Approved :: BSD License
Classifier: Programming Language :: Python :: Implementation :: CPython
*evdev*
-------
This package provides bindings to the generic input event interface in
Linux. The *evdev* interface serves the purpose of passing events
generated in the kernel directly to userspace through character
devices that are typically located in ``/dev/input/``.
This package also comes with bindings to *uinput*, the userspace input
subsystem. *Uinput* allows userspace programs to create and handle
input devices that can inject events directly into the input
subsystem.
Documentation:
http://python-evdev.readthedocs.io/en/latest/
Development:
https://github.com/gvalkov/python-evdev
Package:
http://pypi.python.org/pypi/evdev
Changelog:
http://python-evdev.readthedocs.io/en/latest/changelog.html
evdev-1.4.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
evdev-1.4.0.dist-info/LICENSE,sha256=Bi57JVUB5Zi6BAtQfgd_UcjJFzTCFSCSD3DutcUoCuY,1507
evdev-1.4.0.dist-info/METADATA,sha256=8_d_QgMf5ctbLic6ZA8VmSZucebfE47hYbhks-08RzU,1652
evdev-1.4.0.dist-info/RECORD,,
evdev-1.4.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
evdev-1.4.0.dist-info/WHEEL,sha256=Fs91Ann61S2A_mZ0z4nJS8CwPq9BU-Prnl2pSvzthmM,103
evdev-1.4.0.dist-info/top_level.txt,sha256=tgRM-peDJTah3Is39Micsqkx31ek4FTHG4usyN23Xsk,6
evdev-1.4.0.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
evdev/__init__.py,sha256=AVgqWpkd0uWszPj7gH_iPrqQ5UyfZJfvGwx3fzjJqsg,547
evdev/__pycache__/__init__.cpython-39.pyc,,
evdev/__pycache__/device.cpython-39.pyc,,
evdev/__pycache__/ecodes.cpython-39.pyc,,
evdev/__pycache__/eventio.cpython-39.pyc,,
evdev/__pycache__/eventio_async.cpython-39.pyc,,
evdev/__pycache__/events.cpython-39.pyc,,
evdev/__pycache__/evtest.cpython-39.pyc,,
evdev/__pycache__/ff.cpython-39.pyc,,
evdev/__pycache__/genecodes.cpython-39.pyc,,
evdev/__pycache__/uinput.cpython-39.pyc,,
evdev/__pycache__/util.cpython-39.pyc,,
evdev/_ecodes.cpython-39-x86_64-linux-gnu.so,sha256=D-Kh_53HNQx_H3SJY2mvUE18K2JnokPWbl5nadPlekg,85312
evdev/_input.cpython-39-x86_64-linux-gnu.so,sha256=NN8JmkQWhW2lWfZCde9ozya3hMs3cXuo2pKo1HXKJn0,57736
evdev/_uinput.cpython-39-x86_64-linux-gnu.so,sha256=E6-O1AVTsLvx9YJg5L2WnXGtCIvE_Xo4etOhUC2jnm0,39944
evdev/device.py,sha256=A3tI7k8qooK5zLKrc-vC9N-L_V4RE8Y31hkd-mUjZ1s,12968
evdev/ecodes.py,sha256=2_TtSkfPVZpPqglQEOjDd-47M_Rq3Ca3EWAI29HbeV8,2639
evdev/eventio.py,sha256=NrYb4603GK3MleF5k4pNcCkaSBb27qETIO0h1Mcq6Bk,3961
evdev/eventio_async.py,sha256=VbeM7gUH8UbjyZQpAT3NDjIdnGdKqaQj6eN50tv62FM,2995
evdev/events.py,sha256=Dqo9rWT6j2GiWY8YIFofd82WSnle5YAMzTLB_12bLsk,5794
evdev/evtest.py,sha256=XDFrI9CiHYy8Csj2ll3SnHpBvx1b2fCU7-quSW26MGo,5538
evdev/ff.py,sha256=GJ4y-3bbVEgqo92IJxz9-0WIBGoJmfy3daJIej5dovA,4982
evdev/genecodes.py,sha256=3MVx20AnlCjMsHByWkTGX-01uSuMH8LPbrq6hmP-dvo,2447
evdev/uinput.py,sha256=eL4tcP9aKYdWTSv1ICB_NSdwBl8ffgVgwZI0Xkq86GM,9475
evdev/util.py,sha256=hwgLCGPtDMR1xqddB4rM1YCVqrZ1bCfVWRsPgWF0KZ8,4149
Wheel-Version: 1.0
Generator: bdist_wheel (0.34.2)
Root-Is-Purelib: false
Tag: cp39-cp39-linux_x86_64
#--------------------------------------------------------------------------
# Gather everything into a single, convenient namespace.
#--------------------------------------------------------------------------
from evdev.device import DeviceInfo, InputDevice, AbsInfo, EvdevError
from evdev.events import InputEvent, KeyEvent, RelEvent, SynEvent, AbsEvent, event_factory
from evdev.uinput import UInput, UInputError
from evdev.util import list_devices, categorize, resolve_ecodes, resolve_ecodes_dict
from evdev import ecodes
from evdev import ff
# encoding: utf-8
'''
This modules exposes the integer constants defined in ``linux/input.h`` and
``linux/input-event-codes.h``.
Exposed constants::
KEY, ABS, REL, SW, MSC, LED, BTN, REP, SND, ID, EV,
BUS, SYN, FF, FF_STATUS, INPUT_PROP
This module also provides reverse and forward mappings of the names and values
of the above mentioned constants::
>>> evdev.ecodes.KEY_A
30
>>> evdev.ecodes.ecodes['KEY_A']
30
>>> evdev.ecodes.KEY[30]
'KEY_A'
>>> evdev.ecodes.REL[0]
'REL_X'
>>> evdev.ecodes.EV[evdev.ecodes.EV_KEY]
'EV_KEY'
>>> evdev.ecodes.bytype[evdev.ecodes.EV_REL][0]
'REL_X'
Keep in mind that values in reverse mappings may point to one or more event
codes. For example::
>>> evdev.ecodes.FF[80]
['FF_EFFECT_MIN', 'FF_RUMBLE']
>>> evdev.ecodes.FF[81]
'FF_PERIODIC'
'''
from inspect import getmembers
from evdev import _ecodes
#: Mapping of names to values.
ecodes = {}
prefixes = 'KEY ABS REL SW MSC LED BTN REP SND ID EV BUS SYN FF_STATUS FF INPUT_PROP'
prev_prefix = ''
g = globals()
# eg. code: 'REL_Z', val: 2
for code, val in getmembers(_ecodes):
for prefix in prefixes.split(): # eg. 'REL'
if code.startswith(prefix):
ecodes[code] = val
# FF_STATUS codes should not appear in the FF reverse mapping
if not code.startswith(prev_prefix):
d = g.setdefault(prefix, {})
# codes that share the same value will be added to a list. eg:
# >>> ecodes.FF_STATUS
# {0: 'FF_STATUS_STOPPED', 1: ['FF_STATUS_MAX', 'FF_STATUS_PLAYING']}
if val in d:
if isinstance(d[val], list):
d[val].append(code)
else:
d[val] = [d[val], code]
else:
d[val] = code
prev_prefix = prefix
#: Keys are a combination of all BTN and KEY codes.
keys = {}
keys.update(BTN)
keys.update(KEY)
# make keys safe to use for the default list of uinput device
# capabilities
del keys[_ecodes.KEY_MAX]
del keys[_ecodes.KEY_CNT]
#: Mapping of event types to other value/name mappings.
bytype = {
_ecodes.EV_KEY: keys,
_ecodes.EV_ABS: ABS,
_ecodes.EV_REL: REL,
_ecodes.EV_SW: SW,
_ecodes.EV_MSC: MSC,
_ecodes.EV_LED: LED,
_ecodes.EV_REP: REP,
_ecodes.EV_SND: SND,
_ecodes.EV_SYN: SYN,
_ecodes.EV_FF: FF,
_ecodes.EV_FF_STATUS: FF_STATUS,
}
from evdev._ecodes import *
# cheaper than whitelisting in an __all__
del code, val, prefix, getmembers, g, d, prefixes, prev_prefix
# encoding: utf-8
import os
import fcntl
import select
import functools
from evdev import _input, _uinput, ecodes, util
from evdev.events import InputEvent
#--------------------------------------------------------------------------
class EvdevError(Exception):
pass
class EventIO(object):
'''
Base class for reading and writing input events.
This class is used by :class:`InputDevice` and :class:`UInput`.
- On, :class:`InputDevice` it used for reading user-generated events (e.g.
key presses, mouse movements) and writing feedback events (e.g. leds,
beeps).
- On, :class:`UInput` it used for writing user-generated events (e.g.
key presses, mouse movements) and reading feedback events (e.g. leds,
beeps).
'''
def fileno(self):
'''
Return the file descriptor to the open event device. This makes
it possible to pass instances directly to :func:`select.select()` and
:class:`asyncore.file_dispatcher`.
'''
return self.fd
def read_loop(self):
'''
Enter an endless :func:`select.select()` loop that yields input events.
'''
while True:
r, w, x = select.select([self.fd], [], [])
for event in self.read():
yield event
def read_one(self):
'''
Read and return a single input event as an instance of
:class:`InputEvent <evdev.events.InputEvent>`.
Return ``None`` if there are no pending input events.
'''
# event -> (sec, usec, type, code, val)
event = _input.device_read(self.fd)
if event:
return InputEvent(*event)
def read(self):
'''
Read multiple input events from device. Return a generator object that
yields :class:`InputEvent <evdev.events.InputEvent>` instances. Raises
`BlockingIOError` if there are no available events at the moment.
'''
# events -> [(sec, usec, type, code, val), ...]
events = _input.device_read_many(self.fd)
for event in events:
yield InputEvent(*event)
def need_write(func):
'''
Decorator that raises :class:`EvdevError` if there is no write access to the
input device.
'''
@functools.wraps(func)
def wrapper(*args):
fd = args[0].fd
if fcntl.fcntl(fd, fcntl.F_GETFL) & os.O_RDWR:
return func(*args)
msg = 'no write access to device "%s"' % args[0].path
raise EvdevError(msg)
return wrapper
def write_event(self, event):
'''
Inject an input event into the input subsystem. Events are
queued until a synchronization event is received.
Arguments
---------
event: InputEvent
InputEvent instance or an object with an ``event`` attribute
(:class:`KeyEvent <evdev.events.KeyEvent>`, :class:`RelEvent
<evdev.events.RelEvent>` etc).
Example
-------
>>> ev = InputEvent(1334414993, 274296, ecodes.EV_KEY, ecodes.KEY_A, 1)
>>> ui.write_event(ev)
'''
if hasattr(event, 'event'):
event = event.event
self.write(event.type, event.code, event.value)
@need_write
def write(self, etype, code, value):
'''
Inject an input event into the input subsystem. Events are
queued until a synchronization event is received.
Arguments
---------
etype
event type (e.g. ``EV_KEY``).
code
event code (e.g. ``KEY_A``).
value
event value (e.g. 0 1 2 - depends on event type).
Example
---------
>>> ui.write(e.EV_KEY, e.KEY_A, 1) # key A - down
>>> ui.write(e.EV_KEY, e.KEY_A, 0) # key A - up
'''
_uinput.write(self.fd, etype, code, value)
def close(self):
pass
# encoding: utf-8
import asyncio
import select
from evdev import eventio
# needed for compatibility
from evdev.eventio import EvdevError
class EventIO(eventio.EventIO):
def _do_when_readable(self, callback):
loop = asyncio.get_event_loop()
def ready():
loop.remove_reader(self.fileno())
callback()
loop.add_reader(self.fileno(), ready)
def _set_result(self, future, cb):
try:
future.set_result(cb())
except Exception as error:
future.set_exception(error)
def async_read_one(self):
'''
Asyncio coroutine to read and return a single input event as
an instance of :class:`InputEvent <evdev.events.InputEvent>`.
'''
future = asyncio.Future()
self._do_when_readable(lambda: self._set_result(future, self.read_one))
return future
def async_read(self):
'''
Asyncio coroutine to read multiple input events from device. Return
a generator object that yields :class:`InputEvent <evdev.events.InputEvent>`
instances.
'''
future = asyncio.Future()
self._do_when_readable(lambda: self._set_result(future, self.read))
return future
def async_read_loop(self):
'''
Return an iterator that yields input events. This iterator is
compatible with the ``async for`` syntax.
'''
return ReadIterator(self)
def close(self):
try:
loop = asyncio.get_event_loop()
loop.remove_reader(self.fileno())
except RuntimeError:
# no event loop present, so there is nothing to
# remove the reader from. Ignore
pass
class ReadIterator(object):
def __init__(self, device):
self.current_batch = iter(())
self.device = device
# Standard iterator protocol.
def __iter__(self):
return self
# Python 2.x compatibility.
def next(self):
return self.__next__()
def __next__(self):
try:
# Read from the previous batch of events.
return next(self.current_batch)
except StopIteration:
r, w, x = select.select([self.device.fd], [], [])
self.current_batch = self.device.read()
return next(self.current_batch)
def __aiter__(self):
return self
@asyncio.coroutine
def __anext__(self):
future = asyncio.Future()
try:
# Read from the previous batch of events.
future.set_result(next(self.current_batch))
except StopIteration:
def next_batch_ready(batch):
try:
self.current_batch = batch.result()
future.set_result(next(self.current_batch))
except Exception as e:
future.set_exception(e)
self.device.async_read().add_done_callback(next_batch_ready)
return future
# encoding: utf-8
'''
This module provides the :class:`InputEvent` class, which closely
resembles the ``input_event`` struct defined in ``linux/input.h``:
.. code-block:: c
struct input_event {
struct timeval time;
__u16 type;
__u16 code;
__s32 value;
};
This module also defines several :class:`InputEvent` sub-classes that
know more about the different types of events (key, abs, rel etc). The
:data:`event_factory` dictionary maps event types to these classes.
Assuming you use the :func:`evdev.util.categorize()` function to
categorize events according to their type, adding or replacing a class
for a specific event type becomes a matter of modifying
:data:`event_factory`.
All classes in this module have reasonable ``str()`` and ``repr()``
methods::
>>> print(event)
event at 1337197425.477827, code 04, type 04, val 458792
>>> print(repr(event))
InputEvent(1337197425L, 477827L, 4, 4, 458792L)
>>> print(key_event)
key event at 1337197425.477835, 28 (KEY_ENTER), up
>>> print(repr(key_event))
KeyEvent(InputEvent(1337197425L, 477835L, 1, 28, 0L))
'''
# event type descriptions have been taken mot-a-mot from:
# http://www.kernel.org/doc/Documentation/input/event-codes.txt
from evdev.ecodes import keys, KEY, SYN, REL, ABS, EV_KEY, EV_REL, EV_ABS, EV_SYN
class InputEvent(object):
'''A generic input event.'''
__slots__ = 'sec', 'usec', 'type', 'code', 'value'
def __init__(self, sec, usec, type, code, value):
#: Time in seconds since epoch at which event occurred.
self.sec = sec
#: Microsecond portion of the timestamp.
self.usec = usec
#: Event type - one of ``ecodes.EV_*``.
self.type = type
#: Event code related to the event type.
self.code = code
#: Event value related to the event type.
self.value = value
def timestamp(self):
'''Return event timestamp as a float.'''
return self.sec + (self.usec / 1000000.0)
def __str__(s):
msg = 'event at {:f}, code {:02d}, type {:02d}, val {:02d}'
return msg.format(s.timestamp(), s.code, s.type, s.value)
def __repr__(s):
msg = '{}({!r}, {!r}, {!r}, {!r}, {!r})'
return msg.format(s.__class__.__name__,
s.sec, s.usec, s.type, s.code, s.value)
class KeyEvent(object):
'''An event generated by a keyboard, button or other key-like devices.'''
key_up = 0x0
key_down = 0x1
key_hold = 0x2
__slots__ = 'scancode', 'keycode', 'keystate', 'event'
def __init__(self, event, allow_unknown=False):
'''
The ``allow_unknown`` argument determines what to do in the event of a event code
for which a key code cannot be found. If ``False`` a ``KeyError`` will be raised.
If ``True`` the keycode will be set to the hex value of the event code.
'''
self.scancode = event.code
if event.value == 0:
self.keystate = KeyEvent.key_up
elif event.value == 2:
self.keystate = KeyEvent.key_hold
elif event.value == 1:
self.keystate = KeyEvent.key_down
try:
self.keycode = keys[event.code]
except KeyError:
if allow_unknown:
self.keycode = '0x{:02X}'.format(event.code)
else:
raise
#: Reference to an :class:`InputEvent` instance.
self.event = event
def __str__(self):
try:
ks = ('up', 'down', 'hold')[self.keystate]
except IndexError:
ks = 'unknown'
msg = 'key event at {:f}, {} ({}), {}'
return msg.format(self.event.timestamp(),
self.scancode, self.keycode, ks)
def __repr__(s):
return '{}({!r})'.format(s.__class__.__name__, s.event)
class RelEvent(object):
'''A relative axis event (e.g moving the mouse 5 units to the left).'''
__slots__ = 'event'
def __init__(self, event):
#: Reference to an :class:`InputEvent` instance.
self.event = event
def __str__(self):
msg = 'relative axis event at {:f}, {} '
return msg.format(self.event.timestamp(), REL[self.event.code])
def __repr__(s):
return '{}({!r})'.format(s.__class__.__name__, s.event)
class AbsEvent(object):
'''An absolute axis event (e.g the coordinates of a tap on a touchscreen).'''
__slots__ = 'event'
def __init__(self, event):
#: Reference to an :class:`InputEvent` instance.
self.event = event
def __str__(self):
msg = 'absolute axis event at {:f}, {} '
return msg.format(self.event.timestamp(), ABS[self.event.code])
def __repr__(s):
return '{}({!r})'.format(s.__class__.__name__, s.event)
class SynEvent(object):
'''
A synchronization event. Synchronization events are used as
markers to separate event. Used as markers to separate
events. Events may be separated in time or in space, such as with
the multitouch protocol.
'''
__slots__ = 'event'
def __init__(self, event):
#: Reference to an :class:`InputEvent` instance.
self.event = event
def __str__(self):
msg = 'synchronization event at {:f}, {} '
return msg.format(self.event.timestamp(), SYN[self.event.code])
def __repr__(s):
return '{}({!r})'.format(s.__class__.__name__, s.event)
#: A mapping of event types to :class:`InputEvent` sub-classes. Used
#: by :func:`evdev.util.categorize()`
event_factory = {
EV_KEY: KeyEvent,
EV_REL: RelEvent,
EV_ABS: AbsEvent,
EV_SYN: SynEvent,
}
__all__ = ('InputEvent', 'KeyEvent', 'RelEvent', 'SynEvent',
'AbsEvent', 'event_factory')
# encoding: utf-8
'''
Usage: evtest [options] [<device>, ...]
Input device enumerator and event monitor.
Running evtest without any arguments will let you select
from a list of all readable input devices.
Options:
-h, --help Show this help message and exit.
-c, --capabilities List device capabilities and exit.
-g, --grab Other applications will not receive events from
the selected devices while evtest is running.
Examples:
evtest /dev/input/event0 /dev/input/event1
'''
from __future__ import print_function
import re
import sys
import select
import atexit
import termios
import optparse
try:
input = raw_input
except NameError:
pass
from evdev import ecodes, list_devices, AbsInfo, InputDevice
def parseopt():
parser = optparse.OptionParser(add_help_option=False)
parser.add_option('-h', '--help', action='store_true')
parser.add_option('-g', '--grab', action='store_true')
parser.add_option('-c', '--capabilities', action='store_true')
return parser.parse_args()
def main():
opts, devices = parseopt()
if opts.help:
print(__doc__.strip())
return 0
if not devices:
devices = select_devices()
else:
devices = [InputDevice(path) for path in devices]
if opts.capabilities:
for device in devices:
print_capabilities(device)
return 0
if opts.grab:
for device in devices:
device.grab()
# Disable tty echoing if stdin is a tty.
if sys.stdin.isatty():
toggle_tty_echo(sys.stdin, enable=False)
atexit.register(toggle_tty_echo, sys.stdin, enable=False)
print('Listening for events (press ctrl-c to exit) ...')
fd_to_device = {dev.fd: dev for dev in devices}
while True:
r, w, e = select.select(fd_to_device, [], [])
for fd in r:
for event in fd_to_device[fd].read():
print_event(event)
def select_devices(device_dir='/dev/input'):
'''
Select one or more devices from a list of accessible input devices.
'''
def devicenum(device_path):
digits = re.findall(r'\d+$', device_path)
return [int(i) for i in digits]
devices = sorted(list_devices(device_dir), key=devicenum)
devices = [InputDevice(path) for path in devices]
if not devices:
msg = 'error: no input devices found (do you have rw permission on %s/*?)'
print(msg % device_dir, file=sys.stderr)
sys.exit(1)
dev_format = '{0:<3} {1.path:<20} {1.name:<35} {1.phys:<35} {1.uniq:<4}'
dev_lines = [dev_format.format(num, dev) for num, dev in enumerate(devices)]
print('ID {:<20} {:<35} {:<35} {}'.format('Device', 'Name', 'Phys', 'Uniq'))
print('-' * len(max(dev_lines, key=len)))
print('\n'.join(dev_lines))
print()
choices = input('Select devices [0-%s]: ' % (len(dev_lines) - 1))
try:
choices = choices.split()
choices = [devices[int(num)] for num in choices]
except ValueError:
choices = None
if not choices:
msg = 'error: invalid input - please enter one or more numbers separated by spaces'
print(msg, file=sys.stderr)
sys.exit(1)
return choices
def print_capabilities(device):
capabilities = device.capabilities(verbose=True)
input_props = device.input_props(verbose=True)
print('Device name: {.name}'.format(device))
print('Device info: {.info}'.format(device))
print('Repeat settings: {}\n'.format(device.repeat))
if ('EV_LED', ecodes.EV_LED) in capabilities:
leds = ','.join(i[0] for i in device.leds(True))
print('Active LEDs: %s' % leds)
active_keys = ','.join(k[0] for k in device.active_keys(True))
print('Active keys: %s\n' % active_keys)
if input_props:
print('Input properties:')
for type, code in input_props:
print(' %s %s' % (type, code))
print()
print('Device capabilities:')
for type, codes in capabilities.items():
print(' Type {} {}:'.format(*type))
for code in codes:
# code <- ('BTN_RIGHT', 273) or (['BTN_LEFT', 'BTN_MOUSE'], 272)
if isinstance(code[1], AbsInfo):
print(' Code {:<4} {}:'.format(*code[0]))
print(' {}'.format(code[1]))
else:
# Multiple names may resolve to one value.
s = ', '.join(code[0]) if isinstance(code[0], list) else code[0]
print(' Code {:<4} {}'.format(s, code[1]))
print('')
def print_event(e):
if e.type == ecodes.EV_SYN:
if e.code == ecodes.SYN_MT_REPORT:
msg = 'time {:<16} +++++++++ {} ++++++++'
else:
msg = 'time {:<16} --------- {} --------'
print(msg.format(e.timestamp(), ecodes.SYN[e.code]))
else:
if e.type in ecodes.bytype:
codename = ecodes.bytype[e.type][e.code]
else:
codename = '?'
evfmt = 'time {:<16} type {} ({}), code {:<4} ({}), value {}'
print(evfmt.format(e.timestamp(), e.type, ecodes.EV[e.type], e.code, codename, e.value))
def toggle_tty_echo(fh, enable=True):
flags = termios.tcgetattr(fh.fileno())
if enable:
flags[3] |= termios.ECHO
else:
flags[3] &= ~termios.ECHO
termios.tcsetattr(fh.fileno(), termios.TCSANOW, flags)
if __name__ == '__main__':
try:
ret = main()
except (KeyboardInterrupt, EOFError):
ret = 0
sys.exit(ret)
# encoding: utf-8
import ctypes
from evdev import ecodes
_u8 = ctypes.c_uint8
_u16 = ctypes.c_uint16
_u32 = ctypes.c_uint32
_s16 = ctypes.c_int16
_s32 = ctypes.c_int32
class Replay(ctypes.Structure):
'''
Defines scheduling of the force-feedback effect
@length: duration of the effect
@delay: delay before effect should start playing
'''
_fields_ = [
('length', _u16),
('delay', _u16),
]
class Trigger(ctypes.Structure):
'''
Defines what triggers the force-feedback effect
@button: number of the button triggering the effect
@interval: controls how soon the effect can be re-triggered
'''
_fields_ = [
('button', _u16),
('interval', _u16),
]
class Envelope(ctypes.Structure):
'''
Generic force-feedback effect envelope
@attack_length: duration of the attack (ms)
@attack_level: level at the beginning of the attack
@fade_length: duration of fade (ms)
@fade_level: level at the end of fade
The @attack_level and @fade_level are absolute values; when applying
envelope force-feedback core will convert to positive/negative
value based on polarity of the default level of the effect.
Valid range for the attack and fade levels is 0x0000 - 0x7fff
'''
_fields_ = [
('attack_length', _u16),
('attack_level', _u16),
('fade_length', _u16),
('fade_level', _u16),
]
class Constant(ctypes.Structure):
'''
Defines parameters of a constant force-feedback effect
@level: strength of the effect; may be negative
@envelope: envelope data
'''
_fields_ = [
('level', _s16),
('ff_envelope', Envelope),
]
class Ramp(ctypes.Structure):
'''
Defines parameters of a ramp force-feedback effect
@start_level: beginning strength of the effect; may be negative
@end_level: final strength of the effect; may be negative
@envelope: envelope data
'''
_fields_ = [
('start_level', _s16),
('end_level', _s16),
('ff_envelope', Envelope),
]
class Condition(ctypes.Structure):
'''
Defines a spring or friction force-feedback effect
@right_saturation: maximum level when joystick moved all way to the right
@left_saturation: same for the left side
@right_coeff: controls how fast the force grows when the joystick moves to the right
@left_coeff: same for the left side
@deadband: size of the dead zone, where no force is produced
@center: position of the dead zone
'''
_fields_ = [
('right_saturation', _u16),
('left_saturation', _u16),
('right_coeff', _s16),
('left_coeff', _s16),
('deadband', _u16),
('center', _s16),
]
class Periodic(ctypes.Structure):
'''
Defines parameters of a periodic force-feedback effect
@waveform: kind of the effect (wave)
@period: period of the wave (ms)
@magnitude: peak value
@offset: mean value of the wave (roughly)
@phase: 'horizontal' shift
@envelope: envelope data
@custom_len: number of samples (FF_CUSTOM only)
@custom_data: buffer of samples (FF_CUSTOM only)
'''
_fields_ = [
('waveform', _u16),
('period', _u16),
('magnitude', _s16),
('offset', _s16),
('phase', _u16),
('envelope', Envelope),
('custom_len', _u32),
('custom_data', ctypes.POINTER(_s16)),
]
class Rumble(ctypes.Structure):
'''
Defines parameters of a periodic force-feedback effect
@strong_magnitude: magnitude of the heavy motor
@weak_magnitude: magnitude of the light one
Some rumble pads have two motors of different weight. Strong_magnitude
represents the magnitude of the vibration generated by the heavy one.
'''
_fields_ = [
('strong_magnitude', _u16),
('weak_magnitude', _u16),
]
class EffectType(ctypes.Union):
_fields_ = [
('ff_constant_effect', Constant),
('ff_ramp_effect', Ramp),
('ff_periodic_effect', Periodic),
('ff_condition_effect', Condition * 2), # one for each axis
('ff_rumble_effect', Rumble),
]
class Effect(ctypes.Structure):
_fields_ = [
('type', _u16),
('id', _s16),
('direction', _u16),
('ff_trigger', Trigger),
('ff_replay', Replay),
('u', EffectType)
]
class UInputUpload(ctypes.Structure):
_fields_ = [
('request_id', _u32),
('retval', _s32),
('effect', Effect),
('old', Effect),
]
class UInputErase(ctypes.Structure):
_fields_ = [
('request_id', _u32),
('retval', _s32),
('effect_id', _u32),
]
# ff_types = {
# ecodes.FF_CONSTANT,
# ecodes.FF_PERIODIC,
# ecodes.FF_RAMP,
# ecodes.FF_SPRING,
# ecodes.FF_FRICTION,
# ecodes.FF_DAMPER,
# ecodes.FF_RUMBLE,
# ecodes.FF_INERTIA,
# ecodes.FF_CUSTOM,
# }
# -*- coding: utf-8; -*-
'''
Generate a Python extension module with the constants defined in linux/input.h.
'''
from __future__ import print_function
import os, sys, re
#-----------------------------------------------------------------------------
# The default header file locations to try.
headers = [
'/usr/include/linux/input.h',
'/usr/include/linux/input-event-codes.h',
]
if sys.argv[1:]:
headers = sys.argv[1:]
#-----------------------------------------------------------------------------
macro_regex = r'#define +((?:KEY|ABS|REL|SW|MSC|LED|BTN|REP|SND|ID|EV|BUS|SYN|FF|UI_FF|INPUT_PROP)_\w+)'
macro_regex = re.compile(macro_regex)
uname = list(os.uname()); del uname[1]
uname = ' '.join(uname)
#-----------------------------------------------------------------------------
template = r'''
#include <Python.h>
#ifdef __FreeBSD__
#include <dev/evdev/input.h>
#else
#include <linux/input.h>
#include <linux/uinput.h>
#endif
/* Automatically generated by evdev.genecodes */
/* Generated on %s */
#define MODULE_NAME "_ecodes"
#define MODULE_HELP "linux/input.h macros"
static PyMethodDef MethodTable[] = {
{ NULL, NULL, 0, NULL}
};
#if PY_MAJOR_VERSION >= 3
static struct PyModuleDef moduledef = {
PyModuleDef_HEAD_INIT,
MODULE_NAME,
MODULE_HELP,
-1, /* m_size */
MethodTable, /* m_methods */
NULL, /* m_reload */
NULL, /* m_traverse */
NULL, /* m_clear */
NULL, /* m_free */
};
#endif
static PyObject *
moduleinit(void)
{
#if PY_MAJOR_VERSION >= 3
PyObject* m = PyModule_Create(&moduledef);
#else
PyObject* m = Py_InitModule3(MODULE_NAME, MethodTable, MODULE_HELP);
#endif
if (m == NULL) return NULL;
%s
return m;
}
#if PY_MAJOR_VERSION >= 3
PyMODINIT_FUNC
PyInit__ecodes(void)
{
return moduleinit();
}
#else
PyMODINIT_FUNC
init_ecodes(void)
{
moduleinit();
}
#endif
'''
def parse_header(header):
for line in open(header):
macro = macro_regex.search(line)
if macro:
yield ' PyModule_AddIntMacro(m, %s);' % macro.group(1)
all_macros = []
for header in headers:
try:
fh = open(header)
except (IOError, OSError):
continue
all_macros += parse_header(header)
if not all_macros:
print('no input macros found in: %s' % ' '.join(headers), file=sys.stderr)
sys.exit(1)
macros = os.linesep.join(all_macros)
print(template % (uname, macros))
# encoding: utf-8
import os
import stat
import time
from collections import defaultdict
from evdev import _uinput
from evdev import ecodes, util, device
from evdev.events import InputEvent
import evdev.ff as ff
import ctypes
try:
from evdev.eventio_async import EventIO
except ImportError:
from evdev.eventio import EventIO
class UInputError(Exception):
pass
class UInput(EventIO):
'''
A userland input device and that can inject input events into the
linux input subsystem.
'''
__slots__ = (
'name', 'vendor', 'product', 'version', 'bustype',
'events', 'devnode', 'fd', 'device',
)
@classmethod
def from_device(cls, *devices, **kwargs):
'''
Create an UInput device with the capabilities of one or more input
devices.
Arguments
---------
devices : InputDevice|str
Varargs of InputDevice instances or paths to input devices.
filtered_types : Tuple[event type codes]
Event types to exclude from the capabilities of the uinput device.
**kwargs
Keyword arguments to UInput constructor (i.e. name, vendor etc.).
'''
# TODO: Move back to the argument list once Python 2 support is dropped.
filtered_types = kwargs.pop('filtered_types', (ecodes.EV_SYN, ecodes.EV_FF))
device_instances = []
for dev in devices:
if not isinstance(dev, device.InputDevice):
dev = device.InputDevice(str(dev))
device_instances.append(dev)
all_capabilities = defaultdict(set)
# Merge the capabilities of all devices into one dictionary.
for dev in device_instances:
for ev_type, ev_codes in dev.capabilities().items():
all_capabilities[ev_type].update(ev_codes)
for evtype in filtered_types:
if evtype in all_capabilities:
del all_capabilities[evtype]
return cls(events=all_capabilities, **kwargs)
def __init__(self,
events=None,
name='py-evdev-uinput',
vendor=0x1, product=0x1, version=0x1, bustype=0x3,
devnode='/dev/uinput', phys='py-evdev-uinput', input_props=None):
'''
Arguments
---------
events : dict
Dictionary of event types mapping to lists of event codes. The
event types and codes that the uinput device will be able to
inject - defaults to all key codes.
name
The name of the input device.
vendor
Vendor identifier.
product
Product identifier.
version
Version identifier.
bustype
Bustype identifier.
phys
Physical path.
input_props
Input properties and quirks.
Note
----
If you do not specify any events, the uinput device will be able
to inject only ``KEY_*`` and ``BTN_*`` event codes.
'''
self.name = name #: Uinput device name.
self.vendor = vendor #: Device vendor identifier.
self.product = product #: Device product identifier.
self.version = version #: Device version identifier.
self.bustype = bustype #: Device bustype - e.g. ``BUS_USB``.
self.phys = phys #: Uinput device physical path.
self.devnode = devnode #: Uinput device node - e.g. ``/dev/uinput/``.
if not events:
events = {ecodes.EV_KEY: ecodes.keys.keys()}
self._verify()
#: Write-only, non-blocking file descriptor to the uinput device node.
self.fd = _uinput.open(devnode)
# Prepare the list of events for passing to _uinput.enable and _uinput.setup.
absinfo, prepared_events = self._prepare_events(events)
# Set phys name
_uinput.set_phys(self.fd, phys)
# Set properties
input_props = input_props or []
for prop in input_props:
_uinput.set_prop(self.fd, prop)
for etype, code in prepared_events:
_uinput.enable(self.fd, etype, code)
_uinput.setup(self.fd, name, vendor, product, version, bustype, absinfo)
# Create the uinput device.
_uinput.create(self.fd)
self.dll = ctypes.CDLL(_uinput.__file__)
self.dll._uinput_begin_upload.restype = ctypes.c_int
self.dll._uinput_end_upload.restype = ctypes.c_int
#: An :class:`InputDevice <evdev.device.InputDevice>` instance
#: for the fake input device. ``None`` if the device cannot be
#: opened for reading and writing.
self.device = self._find_device()
def _prepare_events(self, events):
'''Prepare events for passing to _uinput.enable and _uinput.setup'''
absinfo, prepared_events = [], []
for etype, codes in events.items():
for code in codes:
# Handle max, min, fuzz, flat.
if isinstance(code, (tuple, list, device.AbsInfo)):
# Flatten (ABS_Y, (0, 255, 0, 0, 0, 0)) to (ABS_Y, 0, 255, 0, 0, 0, 0).
f = [code[0]]
f.extend(code[1])
# Ensure the tuple is always 6 ints long, since uinput.c:uinput_create
# does little in the way of checking the length.
f.extend([0] * (6 - len(code[1])))
absinfo.append(f)
code = code[0]
prepared_events.append((etype, code))
return absinfo, prepared_events
def __enter__(self):
return self
def __exit__(self, type, value, tb):
if hasattr(self, 'fd'):
self.close()
def __repr__(self):
# TODO:
v = (repr(getattr(self, i)) for i in
('name', 'bustype', 'vendor', 'product', 'version', 'phys'))
return '{}({})'.format(self.__class__.__name__, ', '.join(v))
def __str__(self):
msg = ('name "{}", bus "{}", vendor "{:04x}", product "{:04x}", version "{:04x}", phys "{}"\n'
'event types: {}')
evtypes = [i[0] for i in self.capabilities(True).keys()]
msg = msg.format(self.name, ecodes.BUS[self.bustype],
self.vendor, self.product,
self.version, self.phys, ' '.join(evtypes))
return msg
def close(self):
# Close the associated InputDevice, if it was previously opened.
if self.device is not None:
self.device.close()
# Destroy the uinput device.
if self.fd > -1:
_uinput.close(self.fd)
self.fd = -1
def syn(self):
'''
Inject a ``SYN_REPORT`` event into the input subsystem. Events
queued by :func:`write()` will be fired. If possible, events
will be merged into an 'atomic' event.
'''
_uinput.write(self.fd, ecodes.EV_SYN, ecodes.SYN_REPORT, 0)
def capabilities(self, verbose=False, absinfo=True):
'''See :func:`capabilities <evdev.device.InputDevice.capabilities>`.'''
if self.device is None:
raise UInputError('input device not opened - cannot read capabilities')
return self.device.capabilities(verbose, absinfo)
def begin_upload(self, effect_id):
upload = ff.UInputUpload()
upload.effect_id = effect_id
ret = self.dll._uinput_begin_upload(self.fd, ctypes.byref(upload))
if ret:
raise UInputError('Failed to begin uinput upload: ' + os.strerror(ret))
return upload
def end_upload(self, upload):
ret = self.dll._uinput_end_upload(self.fd, ctypes.byref(upload))
if ret:
raise UInputError('Failed to end uinput upload: ' + os.strerror(ret))
def begin_erase(self, effect_id):
erase = ff.UInputErase()
erase.effect_id = effect_id
ret = self.dll._uinput_begin_erase(self.fd, ctypes.byref(erase))
if ret:
raise UInputError('Failed to begin uinput erase: ' + os.strerror(ret))
return erase
def end_erase(self, erase):
ret = self.dll._uinput_end_erase(self.fd, ctypes.byref(erase))
if ret:
raise UInputError('Failed to end uinput erase: ' + os.strerror(ret))
def _verify(self):
'''
Verify that an uinput device exists and is readable and writable
by the current process.
'''
try:
m = os.stat(self.devnode)[stat.ST_MODE]
if not stat.S_ISCHR(m):
raise
except (IndexError, OSError):
msg = '"{}" does not exist or is not a character device file '\
'- verify that the uinput module is loaded'
raise UInputError(msg.format(self.devnode))
if not os.access(self.devnode, os.W_OK):
msg = '"{}" cannot be opened for writing'
raise UInputError(msg.format(self.devnode))
if len(self.name) > _uinput.maxnamelen:
msg = 'uinput device name must not be longer than {} characters'
raise UInputError(msg.format(_uinput.maxnamelen))
def _find_device(self):
#:bug: the device node might not be immediately available
time.sleep(0.1)
for path in util.list_devices('/dev/input/'):
d = device.InputDevice(path)
if d.name == self.name:
return d
# encoding: utf-8
import re
import os
import stat
import glob
import collections
from evdev import ecodes
from evdev.events import event_factory
def list_devices(input_device_dir='/dev/input'):
'''List readable character devices in ``input_device_dir``.'''
fns = glob.glob('{}/event*'.format(input_device_dir))
fns = list(filter(is_device, fns))
return fns
def is_device(fn):
'''Check if ``fn`` is a readable and writable character device.'''
if not os.path.exists(fn):
return False
m = os.stat(fn)[stat.ST_MODE]
if not stat.S_ISCHR(m):
return False
if not os.access(fn, os.R_OK | os.W_OK):
return False
return True
def categorize(event):
'''
Categorize an event according to its type.
The :data:`event_factory <evdev.events.event_factory>` dictionary
maps event types to sub-classes of :class:`InputEvent
<evdev.events.InputEvent>`. If the event cannot be categorized, it
is returned unmodified.'''
if event.type in event_factory:
return event_factory[event.type](event)
else:
return event
def resolve_ecodes_dict(typecodemap, unknown='?'):
'''
Resolve event codes and types to their verbose names.
:param typecodemap: mapping of event types to lists of event codes.
:param unknown: symbol to which unknown types or codes will be resolved.
Example
-------
>>> resolve_ecodes_dict({ 1: [272, 273, 274] })
{ ('EV_KEY', 1): [('BTN_MOUSE', 272),
('BTN_RIGHT', 273),
('BTN_MIDDLE', 274)] }
If ``typecodemap`` contains absolute axis info (instances of
:class:`AbsInfo <evdev.device.AbsInfo>` ) the result would look
like:
>>> resolve_ecodes_dict({ 3: [(0, AbsInfo(...))] })
{ ('EV_ABS', 3L): [(('ABS_X', 0L), AbsInfo(...))] }
'''
for etype, codes in typecodemap.items():
type_name = ecodes.EV[etype]
# ecodes.keys are a combination of KEY_ and BTN_ codes
if etype == ecodes.EV_KEY:
ecode_dict = ecodes.keys
else:
ecode_dict = getattr(ecodes, type_name.split('_')[-1])
resolved = resolve_ecodes(ecode_dict, codes, unknown)
yield (type_name, etype), resolved
def resolve_ecodes(ecode_dict, ecode_list, unknown='?'):
'''
Resolve event codes and types to their verbose names.
Example
-------
>>> resolve_ecodes(ecodes.BTN, [272, 273, 274])
[(['BTN_LEFT', 'BTN_MOUSE'], 272), ('BTN_RIGHT', 273), ('BTN_MIDDLE', 274)]
'''
res = []
for ecode in ecode_list:
# elements with AbsInfo(), eg { 3 : [(0, AbsInfo(...)), (1, AbsInfo(...))] }
if isinstance(ecode, tuple):
if ecode[0] in ecode_dict:
l = ((ecode_dict[ecode[0]], ecode[0]), ecode[1])
else:
l = ((unknown, ecode[0]), ecode[1])
# just ecodes, e.g: { 0 : [0, 1, 3], 1 : [30, 48] }
else:
if ecode in ecode_dict:
l = (ecode_dict[ecode], ecode)
else:
l = (unknown, ecode)
res.append(l)
return res
def find_ecodes_by_regex(regex):
'''
Find ecodes matching a regex and return a mapping of event type to event codes.
Example
-------
>>> find_ecodes_by_regex(r'(ABS|KEY)_BR(AKE|EAK)')
{1: [411], 3: [10]}
>>> res = find_ecodes_by_regex(r'(ABS|KEY)_BR(AKE|EAK)')
>>> resolve_ecodes_dict(res)
{
('EV_KEY', 1): [('KEY_BREAK', 411)],
('EV_ABS', 3): [('ABS_BRAKE', 10)]
}
'''
regex = regex if isinstance(regex, re.Pattern) else re.compile(regex)
result = collections.defaultdict(list)
for type_code, codes in ecodes.bytype.items():
for code, names in codes.items():
names = (names,) if isinstance(names, str) else names
for name in names:
if regex.match(name):
result[type_code].append(code)
break
return dict(result)
__all__ = ('list_devices', 'is_device', 'categorize', 'resolve_ecodes', 'resolve_ecodes_dict', 'find_ecodes_by_regex')
This software is under the MIT Licence
======================================
Copyright (c) 2010 openpyxl
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Metadata-Version: 2.1
Name: openpyxl
Version: 3.0.9
Summary: A Python library to read/write Excel 2010 xlsx/xlsm files
Home-page: https://openpyxl.readthedocs.io
Author: See AUTHORS
Author-email: charlie.clark@clark-consulting.eu
License: MIT
Project-URL: Documentation, https://openpyxl.readthedocs.io/en/stable/
Project-URL: Source, https://foss.heptapod.net/openpyxl/openpyxl
Project-URL: Tracker, https://foss.heptapod.net/openpyxl/openpyxl/-/issues
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Operating System :: MacOS :: MacOS X
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: POSIX
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Requires-Python: >=3.6
Requires-Dist: et-xmlfile
.. image:: https://coveralls.io/repos/bitbucket/openpyxl/openpyxl/badge.svg?branch=default
:target: https://coveralls.io/bitbucket/openpyxl/openpyxl?branch=default
:alt: coverage status
Introduction
------------
openpyxl is a Python library to read/write Excel 2010 xlsx/xlsm/xltx/xltm files.
It was born from lack of existing library to read/write natively from Python
the Office Open XML format.
All kudos to the PHPExcel team as openpyxl was initially based on PHPExcel.
Security
--------
By default openpyxl does not guard against quadratic blowup or billion laughs
xml attacks. To guard against these attacks install defusedxml.
Mailing List
------------
The user list can be found on http://groups.google.com/group/openpyxl-users
Sample code::
from openpyxl import Workbook
wb = Workbook()
# grab the active worksheet
ws = wb.active
# Data can be assigned directly to cells
ws['A1'] = 42
# Rows can also be appended
ws.append([1, 2, 3])
# Python types will automatically be converted
import datetime
ws['A2'] = datetime.datetime.now()
# Save the file
wb.save("sample.xlsx")
Documentation
-------------
The documentation is at: https://openpyxl.readthedocs.io
* installation methods
* code examples
* instructions for contributing
Release notes: https://openpyxl.readthedocs.io/en/stable/changes.html
Wheel-Version: 1.0
Generator: bdist_wheel (0.36.2)
Root-Is-Purelib: true
Tag: py2-none-any
Tag: py3-none-any
# Copyright (c) 2010-2021 openpyxl
from openpyxl.compat.numbers import NUMPY
from openpyxl.xml import DEFUSEDXML, LXML
from openpyxl.workbook import Workbook
from openpyxl.reader.excel import load_workbook as open
from openpyxl.reader.excel import load_workbook
import openpyxl._constants as constants
# Expose constants especially the version number
__author__ = constants.__author__
__author_email__ = constants.__author_email__
__license__ = constants.__license__
__maintainer_email__ = constants.__maintainer_email__
__url__ = constants.__url__
__version__ = constants.__version__
# Copyright (c) 2010-2021 openpyxl
"""
Package metadata
"""
__author__ = "See AUTHORS"
__author_email__ = "charlie.clark@clark-consulting.eu"
__license__ = "MIT"
__maintainer_email__ = "openpyxl-users@googlegroups.com"
__url__ = "https://openpyxl.readthedocs.io"
__version__ = "3.0.9"
__python__ = "3.6"
# Copyright (c) 2010-2021 openpyxl
from .cell import Cell, WriteOnlyCell, MergedCell
from .read_only import ReadOnlyCell
# Copyright (c) 2010-2021 openpyxl
from openpyxl.compat import safe_string
from openpyxl.xml.functions import Element, SubElement, whitespace, XML_NS, REL_NS
from openpyxl import LXML
from openpyxl.utils.datetime import to_excel, to_ISO8601
from datetime import timedelta
def _set_attributes(cell, styled=None):
"""
Set coordinate and datatype
"""
coordinate = cell.coordinate
attrs = {'r': coordinate}
if styled:
attrs['s'] = f"{cell.style_id}"
if cell.data_type == "s":
attrs['t'] = "inlineStr"
elif cell.data_type != 'f':
attrs['t'] = cell.data_type
value = cell._value
if cell.data_type == "d":
if hasattr(value, "tzinfo") and value.tzinfo is not None:
raise TypeError("Excel does not support timezones in datetimes. "
"The tzinfo in the datetime/time object must be set to None.")
if cell.parent.parent.iso_dates and not isinstance(value, timedelta):
value = to_ISO8601(value)
else:
attrs['t'] = "n"
value = to_excel(value, cell.parent.parent.epoch)
if cell.hyperlink:
cell.parent._hyperlinks.append(cell.hyperlink)
return value, attrs
def etree_write_cell(xf, worksheet, cell, styled=None):
value, attributes = _set_attributes(cell, styled)
el = Element("c", attributes)
if value is None or value == "":
xf.write(el)
return
if cell.data_type == 'f':
shared_formula = worksheet.formula_attributes.get(cell.coordinate, {})
formula = SubElement(el, 'f', shared_formula)
if value is not None:
formula.text = value[1:]
value = None
if cell.data_type == 's':
inline_string = SubElement(el, 'is')
text = SubElement(inline_string, 't')
text.text = value
whitespace(text)
else:
cell_content = SubElement(el, 'v')
if value is not None:
cell_content.text = safe_string(value)
xf.write(el)
def lxml_write_cell(xf, worksheet, cell, styled=False):
value, attributes = _set_attributes(cell, styled)
if value == '' or value is None:
with xf.element("c", attributes):
return
with xf.element('c', attributes):
if cell.data_type == 'f':
shared_formula = worksheet.formula_attributes.get(cell.coordinate, {})
with xf.element('f', shared_formula):
if value is not None:
xf.write(value[1:])
value = None
if cell.data_type == 's':
with xf.element("is"):
attrs = {}
if value != value.strip():
attrs["{%s}space" % XML_NS] = "preserve"
el = Element("t", attrs) # lxml can't handle xml-ns
el.text = value
xf.write(el)
#with xf.element("t", attrs):
#xf.write(value)
else:
with xf.element("v"):
if value is not None:
xf.write(safe_string(value))
if LXML:
write_cell = lxml_write_cell
else:
write_cell = etree_write_cell
# Copyright (c) 2010-2021 openpyxl
"""Manage individual cells in a spreadsheet.
The Cell class is required to know its value and type, display options,
and any other features of an Excel cell. Utilities for referencing
cells using Excel's 'A1' column/row nomenclature are also provided.
"""
__docformat__ = "restructuredtext en"
# Python stdlib imports
from copy import copy
import datetime
import re
from openpyxl.compat import (
NUMERIC_TYPES,
deprecated,
)
from openpyxl.utils.exceptions import IllegalCharacterError
from openpyxl.utils import get_column_letter
from openpyxl.styles import numbers, is_date_format
from openpyxl.styles.styleable import StyleableObject
from openpyxl.worksheet.hyperlink import Hyperlink
# constants
TIME_TYPES = (datetime.datetime, datetime.date, datetime.time, datetime.timedelta)
TIME_FORMATS = {
datetime.datetime:numbers.FORMAT_DATE_DATETIME,
datetime.date:numbers.FORMAT_DATE_YYYYMMDD2,
datetime.time:numbers.FORMAT_DATE_TIME6,
datetime.timedelta:numbers.FORMAT_DATE_TIMEDELTA,
}
STRING_TYPES = (str, bytes)
KNOWN_TYPES = NUMERIC_TYPES + TIME_TYPES + STRING_TYPES + (bool, type(None))
ILLEGAL_CHARACTERS_RE = re.compile(r'[\000-\010]|[\013-\014]|[\016-\037]')
ERROR_CODES = ('#NULL!', '#DIV/0!', '#VALUE!', '#REF!', '#NAME?', '#NUM!',
'#N/A')
TYPE_STRING = 's'
TYPE_FORMULA = 'f'
TYPE_NUMERIC = 'n'
TYPE_BOOL = 'b'
TYPE_NULL = 'n'
TYPE_INLINE = 'inlineStr'
TYPE_ERROR = 'e'
TYPE_FORMULA_CACHE_STRING = 'str'
VALID_TYPES = (TYPE_STRING, TYPE_FORMULA, TYPE_NUMERIC, TYPE_BOOL,
TYPE_NULL, TYPE_INLINE, TYPE_ERROR, TYPE_FORMULA_CACHE_STRING)
_TYPES = {int:'n', float:'n', str:'s', bool:'b'}
def get_type(t, value):
if isinstance(value, NUMERIC_TYPES):
dt = 'n'
elif isinstance(value, STRING_TYPES):
dt = 's'
elif isinstance(value, TIME_TYPES):
dt = 'd'
else:
return
_TYPES[t] = dt
return dt
def get_time_format(t):
value = TIME_FORMATS.get(t)
if value:
return value
for base in t.mro()[1:]:
value = TIME_FORMATS.get(base)
if value:
TIME_FORMATS[t] = value
return value
raise ValueError("Could not get time format for {0!r}".format(value))
class Cell(StyleableObject):
"""Describes cell associated properties.
Properties of interest include style, type, value, and address.
"""
__slots__ = (
'row',
'column',
'_value',
'data_type',
'parent',
'_hyperlink',
'_comment',
)
def __init__(self, worksheet, row=None, column=None, value=None, style_array=None):
super(Cell, self).__init__(worksheet, style_array)
self.row = row
"""Row number of this cell (1-based)"""
self.column = column
"""Column number of this cell (1-based)"""
# _value is the stored value, while value is the displayed value
self._value = None
self._hyperlink = None
self.data_type = 'n'
if value is not None:
self.value = value
self._comment = None
@property
def coordinate(self):
"""This cell's coordinate (ex. 'A5')"""
col = get_column_letter(self.column)
return f"{col}{self.row}"
@property
def col_idx(self):
"""The numerical index of the column"""
return self.column
@property
def column_letter(self):
return get_column_letter(self.column)
@property
def encoding(self):
return self.parent.encoding
@property
def base_date(self):
return self.parent.parent.epoch
def __repr__(self):
return "<Cell {0!r}.{1}>".format(self.parent.title, self.coordinate)
def check_string(self, value):
"""Check string coding, length, and line break character"""
if value is None:
return
# convert to str string
if not isinstance(value, str):
value = str(value, self.encoding)
value = str(value)
# string must never be longer than 32,767 characters
# truncate if necessary
value = value[:32767]
if next(ILLEGAL_CHARACTERS_RE.finditer(value), None):
raise IllegalCharacterError
return value
def check_error(self, value):
"""Tries to convert Error" else N/A"""
try:
return str(value)
except UnicodeDecodeError:
return u'#N/A'
def _bind_value(self, value):
"""Given a value, infer the correct data type"""
self.data_type = "n"
t = type(value)
try:
dt = _TYPES[t]
except KeyError:
dt = get_type(t, value)
if dt is None and value is not None:
raise ValueError("Cannot convert {0!r} to Excel".format(value))
if dt:
self.data_type = dt
if dt == 'd':
if not is_date_format(self.number_format):
self.number_format = get_time_format(t)
elif dt == "s":
value = self.check_string(value)
if len(value) > 1 and value.startswith("="):
self.data_type = 'f'
elif value in ERROR_CODES:
self.data_type = 'e'
self._value = value
@property
def value(self):
"""Get or set the value held in the cell.
:type: depends on the value (string, float, int or
:class:`datetime.datetime`)
"""
return self._value
@value.setter
def value(self, value):
"""Set the value and infer type and display options."""
self._bind_value(value)
@property
def internal_value(self):
"""Always returns the value for excel."""
return self._value
@property
def hyperlink(self):
"""Return the hyperlink target or an empty string"""
return self._hyperlink
@hyperlink.setter
def hyperlink(self, val):
"""Set value and display for hyperlinks in a cell.
Automatically sets the `value` of the cell with link text,
but you can modify it afterwards by setting the `value`
property, and the hyperlink will remain.
Hyperlink is removed if set to ``None``."""
if val is None:
self._hyperlink = None
else:
if not isinstance(val, Hyperlink):
val = Hyperlink(ref="", target=val)
val.ref = self.coordinate
self._hyperlink = val
if self._value is None:
self.value = val.target or val.location
@property
def is_date(self):
"""True if the value is formatted as a date
:type: bool
"""
return self.data_type == 'd' or (
self.data_type == 'n' and is_date_format(self.number_format)
)
def offset(self, row=0, column=0):
"""Returns a cell location relative to this cell.
:param row: number of rows to offset
:type row: int
:param column: number of columns to offset
:type column: int
:rtype: :class:`openpyxl.cell.Cell`
"""
offset_column = self.col_idx + column
offset_row = self.row + row
return self.parent.cell(column=offset_column, row=offset_row)
@property
def comment(self):
""" Returns the comment associated with this cell
:type: :class:`openpyxl.comments.Comment`
"""
return self._comment
@comment.setter
def comment(self, value):
"""
Assign a comment to a cell
"""
if value is not None:
if value.parent:
value = copy(value)
value.bind(self)
elif value is None and self._comment:
self._comment.unbind()
self._comment = value
class MergedCell(StyleableObject):
"""
Describes the properties of a cell in a merged cell and helps to
display the borders of the merged cell.
The value of a MergedCell is always None.
"""
__slots__ = ('row', 'column')
_value = None
data_type = "n"
comment = None
hyperlink = None
def __init__(self, worksheet, row=None, column=None):
super(MergedCell, self).__init__(worksheet)
self.row = row
self.column = column
def __repr__(self):
return "<MergedCell {0!r}.{1}>".format(self.parent.title, self.coordinate)
coordinate = Cell.coordinate
_comment = comment
value = _value
def WriteOnlyCell(ws=None, value=None):
return Cell(worksheet=ws, column=1, row=1, value=value)
# Copyright (c) 2010-2021 openpyxl
from openpyxl.cell import Cell
from openpyxl.utils import get_column_letter
from openpyxl.utils.datetime import from_excel
from openpyxl.styles import is_date_format
from openpyxl.styles.numbers import BUILTIN_FORMATS, BUILTIN_FORMATS_MAX_SIZE
class ReadOnlyCell(object):
__slots__ = ('parent', 'row', 'column', '_value', 'data_type', '_style_id')
def __init__(self, sheet, row, column, value, data_type='n', style_id=0):
self.parent = sheet
self._value = None
self.row = row
self.column = column
self.data_type = data_type
self.value = value
self._style_id = style_id
def __eq__(self, other):
for a in self.__slots__:
if getattr(self, a) != getattr(other, a):
return
return True
def __ne__(self, other):
return not self.__eq__(other)
def __repr__(self):
return "<ReadOnlyCell {0!r}.{1}>".format(self.parent.title, self.coordinate)
@property
def coordinate(self):
column = get_column_letter(self.column)
return "{1}{0}".format(self.row, column)
@property
def coordinate(self):
return Cell.coordinate.__get__(self)
@property
def column_letter(self):
return Cell.column_letter.__get__(self)
@property
def style_array(self):
return self.parent.parent._cell_styles[self._style_id]
@property
def has_style(self):
return self._style_id != 0
@property
def number_format(self):
_id = self.style_array.numFmtId
if _id < BUILTIN_FORMATS_MAX_SIZE:
return BUILTIN_FORMATS.get(_id, "General")
else:
return self.parent.parent._number_formats[
_id - BUILTIN_FORMATS_MAX_SIZE]
@property
def font(self):
_id = self.style_array.fontId
return self.parent.parent._fonts[_id]
@property
def fill(self):
_id = self.style_array.fillId
return self.parent.parent._fills[_id]
@property
def border(self):
_id = self.style_array.borderId
return self.parent.parent._borders[_id]
@property
def alignment(self):
_id = self.style_array.alignmentId
return self.parent.parent._alignments[_id]
@property
def protection(self):
_id = self.style_array.protectionId
return self.parent.parent._protections[_id]
@property
def is_date(self):
return Cell.is_date.__get__(self)
@property
def internal_value(self):
return self._value
@property
def value(self):
return self._value
@value.setter
def value(self, value):
if self._value is not None:
raise AttributeError("Cell is read only")
self._value = value
class EmptyCell(object):
__slots__ = ()
value = None
is_date = False
font = None
border = None
fill = None
number_format = None
alignment = None
data_type = 'n'
def __repr__(self):
return "<EmptyCell>"
EMPTY_CELL = EmptyCell()
# Copyright (c) 2010-2021 openpyxl
"""
Richtext definition
"""
from openpyxl.descriptors.serialisable import Serialisable
from openpyxl.descriptors import (
Alias,
Typed,
Integer,
Set,
NoneSet,
Bool,
String,
Sequence,
)
from openpyxl.descriptors.nested import (
NestedBool,
NestedInteger,
NestedString,
NestedText,
)
from openpyxl.styles.fonts import Font
class PhoneticProperties(Serialisable):
tagname = "phoneticPr"
fontId = Integer()
type = NoneSet(values=(['halfwidthKatakana', 'fullwidthKatakana',
'Hiragana', 'noConversion']))
alignment = NoneSet(values=(['noControl', 'left', 'center', 'distributed']))
def __init__(self,
fontId=None,
type=None,
alignment=None,
):
self.fontId = fontId
self.type = type
self.alignment = alignment
class PhoneticText(Serialisable):
tagname = "rPh"
sb = Integer()
eb = Integer()
t = NestedText(expected_type=str)
text = Alias('t')
def __init__(self,
sb=None,
eb=None,
t=None,
):
self.sb = sb
self.eb = eb
self.t = t
class InlineFont(Font):
"""
Font for inline text because, yes what you need are different objects with the same elements but different constraints.
"""
tagname = "RPrElt"
rFont = NestedString(allow_none=True)
charset = Font.charset
family = Font.family
b =Font.b
i = Font.i
strike = Font.strike
outline = Font.outline
shadow = Font.shadow
condense = Font.condense
extend = Font.extend
color = Font.color
sz = Font.sz
u = Font.u
vertAlign = Font.vertAlign
scheme = Font.scheme
__elements__ = ('rFont', 'charset', 'family', 'b', 'i', 'strike',
'outline', 'shadow', 'condense', 'extend', 'color', 'sz', 'u',
'vertAlign', 'scheme')
def __init__(self,
rFont=None,
charset=None,
family=None,
b=None,
i=None,
strike=None,
outline=None,
shadow=None,
condense=None,
extend=None,
color=None,
sz=None,
u=None,
vertAlign=None,
scheme=None,
):
self.rFont = rFont
self.charset = charset
self.family = family
self.b = b
self.i = i
self.strike = strike
self.outline = outline
self.shadow = shadow
self.condense = condense
self.extend = extend
self.color = color
self.sz = sz
self.u = u
self.vertAlign = vertAlign
self.scheme = scheme
class RichText(Serialisable):
tagname = "RElt"
rPr = Typed(expected_type=InlineFont, allow_none=True)
font = Alias("rPr")
t = NestedText(expected_type=str, allow_none=True)
text = Alias("t")
__elements__ = ('rPr', 't')
def __init__(self,
rPr=None,
t=None,
):
self.rPr = rPr
self.t = t
class Text(Serialisable):
tagname = "text"
t = NestedText(allow_none=True, expected_type=str)
plain = Alias("t")
r = Sequence(expected_type=RichText, allow_none=True)
formatted = Alias("r")
rPh = Sequence(expected_type=PhoneticText, allow_none=True)
phonetic = Alias("rPh")
phoneticPr = Typed(expected_type=PhoneticProperties, allow_none=True)
PhoneticProperties = Alias("phoneticPr")
__elements__ = ('t', 'r', 'rPh', 'phoneticPr')
def __init__(self,
t=None,
r=(),
rPh=(),
phoneticPr=None,
):
self.t = t
self.r = r
self.rPh = rPh
self.phoneticPr = phoneticPr
@property
def content(self):
"""
Text stripped of all formatting
"""
snippets = []
if self.plain is not None:
snippets.append(self.plain)
for block in self.formatted:
if block.t is not None:
snippets.append(block.t)
return u"".join(snippets)
# Copyright (c) 2010-2021 openpyxl
from openpyxl.descriptors import Typed, Alias
from openpyxl.descriptors.serialisable import Serialisable
from openpyxl.descriptors.nested import (
NestedBool,
NestedInteger,
NestedMinMax,
)
from openpyxl.descriptors.excel import ExtensionList
from .marker import PictureOptions
from .shapes import GraphicalProperties
class View3D(Serialisable):
tagname = "view3D"
rotX = NestedMinMax(min=-90, max=90, allow_none=True)
x_rotation = Alias('rotX')
hPercent = NestedMinMax(min=5, max=500, allow_none=True)
height_percent = Alias('hPercent')
rotY = NestedInteger(min=-90, max=90, allow_none=True)
y_rotation = Alias('rotY')
depthPercent = NestedInteger(allow_none=True)
rAngAx = NestedBool(allow_none=True)
right_angle_axes = Alias('rAngAx')
perspective = NestedInteger(allow_none=True)
extLst = Typed(expected_type=ExtensionList, allow_none=True)
__elements__ = ('rotX', 'hPercent', 'rotY', 'depthPercent', 'rAngAx',
'perspective',)
def __init__(self,
rotX=15,
hPercent=None,
rotY=20,
depthPercent=None,
rAngAx=True,
perspective=None,
extLst=None,
):
self.rotX = rotX
self.hPercent = hPercent
self.rotY = rotY
self.depthPercent = depthPercent
self.rAngAx = rAngAx
self.perspective = perspective
class Surface(Serialisable):
tagname = "surface"
thickness = NestedInteger(allow_none=True)
spPr = Typed(expected_type=GraphicalProperties, allow_none=True)
graphicalProperties = Alias('spPr')
pictureOptions = Typed(expected_type=PictureOptions, allow_none=True)
extLst = Typed(expected_type=ExtensionList, allow_none=True)
__elements__ = ('thickness', 'spPr', 'pictureOptions',)
def __init__(self,
thickness=None,
spPr=None,
pictureOptions=None,
extLst=None,
):
self.thickness = thickness
self.spPr = spPr
self.pictureOptions = pictureOptions
class _3DBase(Serialisable):
"""
Base class for 3D charts
"""
tagname = "ChartBase"
view3D = Typed(expected_type=View3D, allow_none=True)
floor = Typed(expected_type=Surface, allow_none=True)
sideWall = Typed(expected_type=Surface, allow_none=True)
backWall = Typed(expected_type=Surface, allow_none=True)
def __init__(self,
view3D=None,
floor=None,
sideWall=None,
backWall=None,
):
if view3D is None:
view3D = View3D()
self.view3D = view3D
if floor is None:
floor = Surface()
self.floor = floor
if sideWall is None:
sideWall = Surface()
self.sideWall = sideWall
if backWall is None:
backWall = Surface()
self.backWall = backWall
super(_3DBase, self).__init__()
# Copyright (c) 2010-2021 openpyxl
from .area_chart import AreaChart, AreaChart3D
from .bar_chart import BarChart, BarChart3D
from .bubble_chart import BubbleChart
from .line_chart import LineChart, LineChart3D
from .pie_chart import (
PieChart,
PieChart3D,
DoughnutChart,
ProjectedPieChart
)
from .radar_chart import RadarChart
from .scatter_chart import ScatterChart
from .stock_chart import StockChart
from .surface_chart import SurfaceChart, SurfaceChart3D
from .series_factory import SeriesFactory as Series
from .reference import Reference
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment