diff --git a/.gitignore b/.gitignore index f17c274d..1bfc589d 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ *.o *.pyc *.log +.idea /openzwave/ build/ dists/ diff --git a/.travis.yml b/.travis.yml index 081d91ee..0b787937 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,9 @@ env: matrix: - DOCKER_BASE=ubuntu:latest - DOCKER_BASE=debian:latest + - DOCKER_BASE=i386/ubuntu:xenial + #~ - DOCKER_BASE=arm32v7/ubuntu:xenial + #~ - DOCKER_BASE=arm64v8/ubuntu:xenial #~ - DOCKER_BASE=resin/rpi-raspbian:latest - DOCS="true" global: @@ -17,7 +20,8 @@ before_install: docker pull ${DOCKER_BASE}; fi - if [[ "${DOCS}" == "true" ]]; then - sudo apt install -y libudev-dev; + sudo apt-get update; + sudo make common-deps; fi script: - if [[ "${DOCKER_BASE}x" != "x" ]]; then diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 40f19d7b..1b504fd0 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,10 +1,69 @@ Changelog ********* -python_openzwave 0.4.3.x: +python_openzwave 0.4.18.x: + * Fix python 2.7/appveyor + + * Add serial port auto-detection + +python_openzwave 0.4.17.x: + * Add wheels for Windows + +python_openzwave 0.4.16.x: + * Fix appveyor build for windows + +python_openzwave 0.4.15.x: + * Update embeded package + +python_openzwave 0.4.14.x: + * Use Cython 0.28.6 + + * Update embeded package + +python_openzwave 0.4.12.x: + * Improve support Windows + + * COMMAND_CLASS_ZWAVE_PLUS_INFO renamed to + COMMAND_CLASS_ZWAVEPLUS_INFO + + * Update thermostat + + * Update embeded package + +python_openzwave 0.4.11.x: + * Update embeded package + +python_openzwave 0.4.10.x: + * Improve support Windows in pip + + * Improve tests Windows + + * Update contructors for scenes and groups + +python_openzwave 0.4.9.x: + * Improve support Windows in pip + + * Update tests + +python_openzwave 0.4.6.x: + * First try to support Windows in pip + +python_openzwave 0.4.5.x: + * Fix bug in node statistics and add test. + + * Update Makefile to build flavor dev + + * Update pyozw_check. + + * Update default flavor : check cython is here before choosing + shared + + * Fix controller.update_ozw_config when directory isn't writable + +python_openzwave 0.4.4.x: * Add new options to pyozw_check to list nodes on network. -python_openzwave 0.4.2.x: +python_openzwave 0.4.3.x: * Fix bug in default flavor. python_openzwave 0.4.1.x: diff --git a/DEVEL.txt b/DEVEL.txt index a0382730..f2d8f06b 100644 --- a/DEVEL.txt +++ b/DEVEL.txt @@ -5,88 +5,44 @@ Developers information How to develop for python-openzwave =================================== -Get the sources +Fork the project on Github. - git clone https://github.com/OpenZWave/python-openzwave +Get the sources : + + git clone https://github.com/yourname/python-openzwave You can install all the dependances to develop for python-openzwave using the command : sudo make developer-deps -You must now install python-openzwave in develop mode +You must now install python-openzwave in develop mode. Depending on +which python version you prefer, use : + + make venv2-dev - make develop +or -Your password will be asked (by sudo) for installing eggs in your -local directory. + make venv2-dev + +Keep in mind that your updates must be python 2 / python 3 compatible. Develop, test, debug, test, ... :) Update the documentation if needed. You surely found the documentation useful, so please keep it up to date. -You can create an account on travis or docker to run the tests. - -At last but not least, submit your request. - - -How to develop for libopenzwave (was python-openzwave-lib) -========================================================== - -After updating the pyx, you need to reinstall it. Otherwise, your -changes will not be applied : - - make develop - - -Tests -===== - -First, install the dependances : - - sudo make tests-deps - -To launch all the tests suite (about 140 tests), use the following -command : +It a good idea to add automatic tests. - make tests +Launch the full test suite (for python 2 and python 3) : -To launch particular tests : + make venv-tests - nosetests --verbosity=2 tests/api/test_controller_command.py +At last but not least, submit your request with the result of tests in +the comment. -Some tests need manual operations (ie to add a node, to remove one, -...). For example, to test the remove node, use : - - export MANUALSKIP='False' && nosetests --verbosity=2 tests/api/test_controller_command.py -m test_150 && unset MANUALSKIP - test_150_command_remove_node_and_wait_for_user (tests.api.test_controller_command.TestControllerCommand) ... ok - - ---------------------------------------------------------------------- - Ran 1 test in 16.031s - - OK - -You should push the inclusion button of the node before the end of the -test. - -Some tests don't need a ZWave Stick to be launched, so they can be run -on the autobuilders (travis, docker, ...). Place them in the autobuild -directory. - -Travis-ci, Docker Hub, nosetests and pylint are used to test quality -of code. There reports are here : - - * Docker : https://registry.hub.docker.com/u/bibi21000/python- - openzwave/ - - * Travis : https://travis-ci.org/bibi21000/python-openzwave - - * Nosetests report - - * Coverage report - - * Pylint report +If you don't follow the previous steps, your PR will be refused or +letting in pending state until I've got time to test it. Documentation @@ -96,97 +52,7 @@ First, install the dependances : sudo make doc-deps -Documentation is managed with sphinx. Don't utpdate txt files (README, -INSTALL, ...), update the RST sources in docs. Use the following -commands to generate all docs files (txt, html and joomla) - -You need to have installed python-openzwave (in either develop or -install mode) before generating the documentation. - - make docs - - -Static vs dynamic (or shared) -============================= - -The openzwave (c++) lib needs to run as a singleton : it means that it -MUST have only one instance of the manager running on your computer. - -There is 2 ways of linking libraries with a program : - - * static : includes a copy of the library in your binary program. - This means that your program has its own instance of the library. - This the way the install.sh runs. So you CAN'T have another - program (like the control-panel) running when using the python- - openzwave library - - * dynamic or shared : includes a link to the library in your - binary program. This means that your program share the library - with other programs. In this case, the instance is owned directly - by the library. This the way the debian package works. So you CAN - have another program running when using the python-openzwave - library. Of course, this program MUST use the shared library too. - - -About sudo -========== - -If you are like me and don't like root (and sudo), you can use the -following tip to install packages via pip : - -Look at your python local library, it should looks like : - - ls -lisa /usr/local/lib/python2.7/dist-packages/ - total 2428 - 1445174 12 drwxrwsr-x 115 root staff 12288 avril 9 21:35 . - 1445172 4 drwxrwsr-x 4 root staff 4096 mai 2 2014 .. - 1457164 4 drwxr-sr-x 5 root staff 4096 nov. 26 2013 actdiag - 1715480 4 drwxr-sr-x 2 root staff 4096 nov. 26 2013 actdiag-0.5.1.egg-info - 1457163 4 -rw-r--r-- 1 root staff 1004 nov. 26 2013 actdiag_sphinxhelper.py - 1457172 4 -rw-r--r-- 1 root staff 620 nov. 26 2013 actdiag_sphinxhelper.pyc - .... - -So, add your common user to the staff group : - - sudo usermod -a -G staff userName - -Add the write right to the group staff - - sudo chmod -Rf g+w /usr/local/lib/python2.7/dist-packages/ - -And now, it's time log off and log on. Groups are checked when you -open the session. - -You can now install your packages without sudo. - - -Python3 and virtualenv -====================== - -Python 3 is actually not supported. - -A branch (python3) has been created with a special Dockerfile. It -build python-openzwave and launch some tests. This branch is -automatically merged from master at "make commit". - -So please, do not directly push under python3 branch. Make your -developments under master or another branch. - -It's important for me have python2/python3 compatibilty in the master -branch. cython can help for this : -http://docs.cython.org/src/tutorial/strings.html - -The Makefile sill try to automatically configure your version of -python (running python --version). - -If you want to install python-openzwave in a python virtual -environnement, you should use something like : - - make VIRTUAL_ENV=/path/to/my/venv ... - -If you use python 3 and your python executable is called python3 : - - make PYTHON_EXEC=python3 ... +Documentation is managed with sphinx. -You can also put these variables in a CONFIG.make file instead of -passing them to the command line +Don't update txt and rst files (README, INSTALL, ...) in the root +directory, update the RST sources in docs. diff --git a/INSTALL_WIN.rst b/INSTALL_WIN.rst index f95d213c..6ced83fc 100755 --- a/INSTALL_WIN.rst +++ b/INSTALL_WIN.rst @@ -5,54 +5,183 @@ Installing python-openzwave on Windows ====================================== -This HOW-TO is for 0.4.X. +Install Microsoft tools +======================= -It should be possible to make it pip friendly. Need a command line to build openzwave c++ lib. +This package use MSBuild.exe to build openzwave code. -How To Build python-openzwave on Windows with VS2015 -==================================================== +You can find it in Visual Studio 2017 or Visual Studio 2015. -Assuming Python 3.5 is set in PATH -Assuming your python environment has pip, cython, setuptools +It's also possible to get it as a separate package. +Only release 14.0 and 15.0 of Microsft Build Tools are tested. -Get sources ------------ +You nust use the C++ compiler used to build your version of python : https://wiki.python.org/moin/WindowsCompilers -.. code-block:: bash - git clone https://github.com/openzwave/python-openzwave.git +Install other tools +=================== - cd python-openzwave - git clone git://github.com/OpenZWave/open-zwave.git openzwave +You need git to clone the repository and python (32 bits or 64 bits). Add it to your PATH. + +Install dependencies : + + - for python 2.7 : - cd openzwave - git checkout Dev - cd .. - git checkout + .. code-block:: bash + (venvX) pip install Cython six Louie -Build open-zwave ----------------- + - for python 3 : -Open openzwave/cpp/build/windows/vs2010/OpenZWave.sln in Visual Studio + .. code-block:: bash -When asked, accept the project upgrade to VS2015 + (venvX) pip install Cython six PyDispatcher -Build Win32|Release +clone repositories +================== +Clone python-openzwave: + + +.. code-block:: bash -Build python_openzwave ----------------------- + git clone https://github.com/OpenZWave/python-openzwave.git -From a Command Prompt, install it : +And clone open-zwave inside python-openzwave : .. code-block:: bash - python setup install --dev + cd python-openzwave + git clone https://github.com/OpenZWave/open-zwave.git openzwave + +It's mandatory to clone the previous repository in a directory called openzwave (not open-zwave) + +Visual studio +============= + +Copy vs2010 in a new directory vs2017 (or vs2015 depending of which Visual Studio you use) : + +.. code-block:: bash -Reference for 0.3.X : https://github.com/OpenZWave/python-openzwave/issues/53 + xcopy openzwave\cpp\build\windows\vs2010 openzwave\cpp\build\windows\vs2017 /s /e /h + +Open the project (openzwave\cpp\build\windows\vs2017\OpenZWave.sln) in your Visual Studio. +If you want to build for 64bits, add a new target for it. And finally close it. + +Python-openzwave +================ + +Build and install python-openzwave : + + .. code-block:: bash + + python setup.py install --flavor=dev + + .. code-block:: bash + + sysargv ['setup.py', 'install'] + thon setup.py install --flavor=dev + Requirement already satisfied: Cython in c:\program files (x86)\python36-32\lib\site-packages + {'name': 'libopenzwave', 'sources': ['src-lib/libopenzwave/libopenzwave.pyx'], 'include_dirs': ['openzwave/cpp/src', 'openzwave + /cpp/src/value_classes', 'openzwave/cpp/src/platform', 'openzwave/cpp/build/windows', 'src-lib/libopenzwave', 'openzwave/cpp/bu + ild/windows/vs2017/Release/'], 'define_macros': [('PY_LIB_VERSION', '0.4.4'), ('PY_SSIZE_T_CLEAN', 1), ('PY_LIB_FLAVOR', 'dev') + , ('PY_LIB_BACKEND', 'cython')], 'libraries': ['setupapi', 'msvcrt', 'ws2_32', 'dnsapi'], 'extra_objects': ['openzwave/cpp/buil + d/windows/vs2017/Release//OpenZWave.lib'], 'extra_compile_args': [], 'extra_link_args': [], 'language': 'c++'} + ['six', 'PyDispatcher>=2.0.5', 'Cython'] + Requirement already satisfied: Cython in c:\program files (x86)\python36-32\lib\site-packages + running install + flavor --flavor=dev c:\program files (x86)\python36-32\lib\site-packages + running build_openzwave + Found MSBuild.exe : c:/Program Files (x86)/Microsoft Visual Studio\2017\BuildTools\MSBuild\15.0\Bin\MSBuild.exe + Found arch : Win32 wave + Found Visual Studio project : vs2017 (x86)/Microsoft Visual Studio\2017\BuildTools\MSBuild\15.0\Bin\MSBuild.exe + Found build path : openzwave/cpp/build/windows/vs2017/Release/ + ... + ... + byte-compiling C:\Program Files (x86)\Python36-32\Lib\site-packages\python_openzwave\scripts\__init__.py to __init__.cpython-36 + .pyc + running install_egg_info + running egg_info + writing python_openzwave.egg-info\PKG-INFO + writing dependency_links to python_openzwave.egg-info\dependency_links.txt + writing entry points to python_openzwave.egg-info\entry_points.txt + ================================================================ + .\scripts\allusers.bat + this script is executed for all users + delete/rename it if you dont need it + ================================================================ + Page de codes active�: 437 + +And finally, test it : + + .. code-block:: bash + + pyozw_check -l -d COM2 -t 30 + + .. code-block:: bash + + ------------------------------------------------------------------------------- + Define options for device COM2 + Start network + Wait for network awake (30s) + ------------------------------------------------------------------------------- + Network is awaked. Talk to controller. + Get python_openzwave version : 0.4.4 + Get python_openzwave config version : Original Z-Wave 2.78 + Get python_openzwave flavor : dev + Get openzwave version : 1.4.2942 + Get config path : C:\Program Files\Python36\lib\site-packages\python_openzwave\ozw_config + Controller capabilities : {'primaryController', 'staticUpdateController'} + Controller node capabilities : {'listening', 'primaryController', 'beaming', 'staticUpdateController'} + Nodes in network : 4 + ------------------------------------------------------------------------------- + Wait for network ready (30s) + ------------------------------------------------------------------------------- + Network is ready. Get nodes + ------------------------------------------------------------ + 1 - Name : ( Location : ) + 1 - Ready : True / Awake : True / Failed : False + 1 - Manufacturer : Aeotec ( id : 0x0086 ) + 1 - Product : DSA02203 Z-Stick S2 ( id : 0x0001 / type : 0x0002 / Version : 3) + 1 - Command classes : set() + 1 - Capabilities : {'listening', 'primaryController', 'beaming', 'staticUpdateController'} + 1 - Neighbors : {4} / Power level : None + 1 - Is sleeping : False / Can wake-up : False / Battery level : None + ------------------------------------------------------------ + 2 - Name : ( Location : ) + 2 - Ready : True / Awake : True / Failed : False + 2 - Manufacturer : ( id : 0x0000 ) + 2 - Product : ( id : 0x0000 / type : 0x0000 / Version : 2) + 2 - Command classes : set() + 2 - Capabilities : {'listening', 'routing'} + 2 - Neighbors : {3} / Power level : None + 2 - Is sleeping : False / Can wake-up : False / Battery level : None + ------------------------------------------------------------ + 3 - Name : ( Location : ) + 3 - Ready : False / Awake : True / Failed : True + 3 - Manufacturer : ( id : 0x0000 ) + 3 - Product : ( id : 0x0000 / type : 0x0000 / Version : 3) + 3 - Command classes : set() + 3 - Capabilities : {'listening', 'routing', 'beaming'} + 3 - Neighbors : set() / Power level : None + 3 - Is sleeping : False / Can wake-up : False / Battery level : None + ------------------------------------------------------------ + 4 - Name : ( Location : ) + 4 - Ready : True / Awake : True / Failed : False + 4 - Manufacturer : GreenWave ( id : 0x0099 ) + 4 - Product : PowerNode 6 port ( id : 0x0004 / type : 0x0003 / Version : 4) + 4 - Command classes : {'COMMAND_CLASS_MANUFACTURER_SPECIFIC', 'COMMAND_CLASS_ASSOCIATION', 'COMMAND_CLASS_NO_OPERATION', 'COMM + AND_CLASS_VERSION', 'COMMAND_CLASS_SWITCH_BINARY', 'COMMAND_CLASS_MULTI_INSTANCE/CHANNEL', 'COMMAND_CLASS_CRC_16_ENCAP', 'COMMA + ND_CLASS_PROTECTION', 'COMMAND_CLASS_CONFIGURATION', 'COMMAND_CLASS_BASIC', 'COMMAND_CLASS_METER', 'COMMAND_CLASS_SWITCH_ALL'} + 4 - Capabilities : {'listening', 'routing', 'beaming'} + 4 - Neighbors : {1} / Power level : None + 4 - Is sleeping : False / Can wake-up : False / Battery level : None + ------------------------------------------------------------ + Driver statistics : {'SOFCnt': 49, 'ACKWaiting': 0, 'readAborts': 0, 'badChecksum': 0, 'readCnt': 49, 'writeCnt': 46, 'CANCnt': + 0, 'NAKCnt': 1, 'ACKCnt': 30, 'OOFCnt': 0, 'dropped': 17, 'retries': 0, 'callbacks': 0, 'badroutes': 0, 'noack': 4, 'netbusy': + 0, 'nondelivery': 0, 'routedbusy': 0, 'broadcastReadCnt': 0, 'broadcastWriteCnt': 9} + ------------------------------------------------------------ + Stop network + Exit -Cygwin ------- -python3 diff --git a/Makefile b/Makefile index d241f3c1..9bb1a49b 100644 --- a/Makefile +++ b/Makefile @@ -157,7 +157,7 @@ endif ifeq (${python_version_major},3) apt-get install --force-yes -y cython3 endif - + ci-deps: apt-get install --force-yes -y python-pip python-dev python-docutils python-setuptools python-virtualenv -apt-get install --force-yes -y python3-pip python3-docutils python3-dev python3-setuptools @@ -387,6 +387,8 @@ pypi_package:clean-archive cp -f pyozw_pkgconfig.py $(ARCHBASE)/python_openzwave/ cp -f pyozw_setup.py $(ARCHBASE)/python_openzwave/ cp -f pyozw_version.py $(ARCHBASE)/python_openzwave/ + cp -f pyozw_win.py $(ARCHBASE)/python_openzwave/ + cp -f pyozw_progressbar.py $(ARCHBASE)/python_openzwave/ cp -f python_openzwave.egg-info/PKG-INFO $(ARCHBASE)/python_openzwave/ -find $(ARCHBASE)/python_openzwave/ -name \*.pyc -delete 2>/dev/null || true -find $(ARCHBASE)/python_openzwave/ -name \*.so -delete 2>/dev/null || true @@ -417,7 +419,7 @@ commit: push @echo "Commits for branches master pushed on github." tag: - git tag v${python_openzwave_version} + -git tag v${python_openzwave_version} git push origin v${python_openzwave_version} @echo @echo "Tag pushed on github." @@ -497,7 +499,7 @@ venv-deps: common-deps apt-get install --force-yes -y python-all python-dev python3-all python3-dev python-virtualenv python-pip #~ apt-get install --force-yes -y python-wheel-common python3-wheel python-wheel python-pip-whl apt-get install --force-yes -y pkg-config wget unzip zip - pip install Cython + pip install Cython==0.28.6 pip install wheel docker-deps: common-deps @@ -505,8 +507,8 @@ docker-deps: common-deps apt-get install --force-yes -y python3-pip python-pip python-wheel python3-wheel python-pip-whl apt-get install --force-yes -y wget unzip zip apt-get install --force-yes -y g++ libudev-dev libyaml-dev - pip install cython - pip3 install cython + pip install Cython==0.28.6 + pip3 install Cython==0.28.6 venv2: @echo //////////////////////////////////////////////////////////////////////////////////////////// @@ -518,7 +520,7 @@ venv2: virtualenv --python=python2 venv2 venv2/bin/python --version venv2/bin/pip install nose - venv2/bin/pip install Cython wheel six + venv2/bin/pip install Cython==0.28.6 wheel six pyserial venv2/bin/pip install 'Louie>=1.1' chmod 755 venv2/bin/activate -rm -f src-lib/libopenzwave/libopenzwave.cpp @@ -540,7 +542,7 @@ venv3: virtualenv --python=python3 venv3 venv3/bin/python --version venv3/bin/pip install nose - venv3/bin/pip install Cython wheel six + venv3/bin/pip install Cython==0.28.6 wheel six pyserial venv3/bin/pip install 'PyDispatcher>=2.0.5' chmod 755 venv3/bin/activate -rm -f src-lib/libopenzwave/libopenzwave.cpp @@ -588,12 +590,6 @@ venv-tests: venv2-tests venv3-tests venv2-tests: venv2-dev @echo ========================================================================================== - @echo - @echo - @echo "Launch tests for venv-autobuild-autobuild-tests." - @echo - @echo - @echo @echo //////////////////////////////////////////////////////////////////////////////////////////// @echo @@ -601,6 +597,7 @@ venv2-tests: venv2-dev @echo @echo //////////////////////////////////////////////////////////////////////////////////////////// @echo + -$(MAKE) PYTHON_EXEC=venv2/bin/python NOSE_EXEC=venv2/bin/nosetests tests @echo @@ -619,6 +616,7 @@ venv3-tests: venv3-dev @echo @echo //////////////////////////////////////////////////////////////////////////////////////////// @echo + -$(MAKE) PYTHON_EXEC=venv3/bin/python NOSE_EXEC=venv3/bin/nosetests tests @echo @@ -740,14 +738,14 @@ venv-pypitest-autobuild-tests: venv-clean venv2 venv3 -rm -f libopenzwave*.so venv2/bin/pip install "urwid>=1.1.1" - venv2/bin/pip install -i https://testpypi.python.org/pypi -vvv python_openzwave + venv2/bin/pip install -i https://pypi.python.org/pypi -vvv python_openzwave venv2/bin/nosetests --verbose tests/lib/autobuild tests/api/autobuild tests/manager/autobuild venv2/bin/python venv2/bin/pyozw_check -o raw|grep '(embed-' venv2/bin/pip install "Cython" venv2/bin/pip uninstall python_openzwave -y - venv2/bin/pip install -i https://testpypi.python.org/pypi -vvv python_openzwave --install-option="--flavor=git" + venv2/bin/pip install -i https://pypi.python.org/pypi -vvv python_openzwave --install-option="--flavor=git" venv2/bin/nosetests --verbose tests/lib/autobuild tests/api/autobuild tests/manager/autobuild - venv2/bin/pip install -i https://testpypi.python.org/pypi -vvv python_openzwave --force --install-option="--flavor=git" + venv2/bin/pip install -i https://pypi.python.org/pypi -vvv python_openzwave --force --install-option="--flavor=git" venv2/bin/nosetests --verbose tests/lib/autobuild tests/api/autobuild tests/manager/autobuild venv2/bin/python venv2/bin/pyozw_check venv2/bin/python venv2/bin/pyozw_shell --help @@ -764,14 +762,14 @@ venv-pypitest-autobuild-tests: venv-clean venv2 venv3 -rm -f libopenzwave*.so venv3/bin/pip install "urwid>=1.1.1" - venv3/bin/pip install -i https://testpypi.python.org/pypi -vvv python_openzwave + venv3/bin/pip install -i https://pypi.python.org/pypi -vvv python_openzwave venv3/bin/nosetests --verbose tests/lib/autobuild tests/api/autobuild tests/manager/autobuild venv3/bin/python venv3/bin/pyozw_check -o raw|grep '(embed-' venv3/bin/pip install "Cython" venv3/bin/pip uninstall python_openzwave -y - venv3/bin/pip install -i https://testpypi.python.org/pypi -vvv python_openzwave --install-option="--flavor=git" + venv3/bin/pip install -i https://pypi.python.org/pypi -vvv python_openzwave --install-option="--flavor=git" venv3/bin/nosetests --verbose tests/lib/autobuild tests/api/autobuild tests/manager/autobuild - venv3/bin/pip install -i https://testpypi.python.org/pypi -vvv python_openzwave --force --install-option="--flavor=git" + venv3/bin/pip install -i https://pypi.python.org/pypi -vvv python_openzwave --force --install-option="--flavor=git" venv3/bin/nosetests --verbose tests/lib/autobuild tests/api/autobuild tests/manager/autobuild venv3/bin/python venv3/bin/pyozw_check venv3/bin/python venv3/bin/pyozw_shell --help @@ -810,16 +808,22 @@ venv-pypilive-autobuild-tests: venv-clean venv2/bin/pip install "urwid>=1.1.1" venv2/bin/pip install "nose" venv2/bin/pip install -vv python_openzwave + venv2/bin/python venv2/bin/pyozw_check -o raw venv2/bin/python venv2/bin/pyozw_check -o raw|grep '(embed-' venv2/bin/nosetests --verbose tests/lib/autobuild tests/api/autobuild tests/manager/autobuild -#~ venv2/bin/pip install Cython wheel - venv2/bin/pip install -vv python_openzwave --upgrade --install-option="--flavor=git" - venv2/bin/nosetests --verbose tests/lib/autobuild tests/api/autobuild tests/manager/autobuild + venv2/bin/pip install Cython==0.28.6 +#~ venv2/bin/pip install wheel venv2/bin/pip uninstall python_openzwave -y venv2/bin/pip install -vv python_openzwave --upgrade --install-option="--flavor=git" venv2/bin/nosetests --verbose tests/lib/autobuild tests/api/autobuild tests/manager/autobuild + venv2/bin/python venv2/bin/pyozw_check -o raw venv2/bin/python venv2/bin/pyozw_check -o raw|grep '(git-' venv2/bin/pip uninstall python_openzwave -y + venv2/bin/pip install -vv python_openzwave --upgrade --install-option="--flavor=ozwdev" + venv2/bin/nosetests --verbose tests/lib/autobuild tests/api/autobuild tests/manager/autobuild + venv2/bin/python venv2/bin/pyozw_check -o raw + venv2/bin/python venv2/bin/pyozw_check -o raw|grep '(ozwdev-' + venv2/bin/pip uninstall python_openzwave -y @echo @echo //////////////////////////////////////////////////////////////////////////////////////////// @@ -837,16 +841,22 @@ venv-pypilive-autobuild-tests: venv-clean venv3/bin/pip install "nose" venv3/bin/pip install "urwid>=1.1.1" venv3/bin/pip install -vv python_openzwave + venv3/bin/python venv3/bin/pyozw_check -o raw venv3/bin/python venv3/bin/pyozw_check -o raw|grep '(embed-' venv3/bin/nosetests --verbose tests/lib/autobuild tests/api/autobuild tests/manager/autobuild -#~ venv3/bin/pip install Cython wheel - venv3/bin/pip install -vv python_openzwave --upgrade --install-option="--flavor=git" - venv3/bin/nosetests --verbose tests/lib/autobuild tests/api/autobuild tests/manager/autobuild + venv3/bin/pip install Cython==0.28.6 +#~ venv3/bin/pip install wheel venv3/bin/pip uninstall python_openzwave -y venv3/bin/pip install -vv python_openzwave --upgrade --install-option="--flavor=git" venv3/bin/nosetests --verbose tests/lib/autobuild tests/api/autobuild tests/manager/autobuild + venv3/bin/python venv3/bin/pyozw_check -o raw venv3/bin/python venv3/bin/pyozw_check -o raw|grep '(git-' venv3/bin/pip uninstall python_openzwave -y + venv3/bin/pip install -vv python_openzwave --upgrade --install-option="--flavor=ozwdev" + venv3/bin/nosetests --verbose tests/lib/autobuild tests/api/autobuild tests/manager/autobuild + venv3/bin/python venv3/bin/pyozw_check -o raw + venv3/bin/python venv3/bin/pyozw_check -o raw|grep '(ozwdev-' + venv3/bin/pip uninstall python_openzwave -y -rm -f libopenzwave*.so @echo diff --git a/README.rst b/README.rst index 92dae159..c4ae7c44 100755 --- a/README.rst +++ b/README.rst @@ -6,6 +6,10 @@ :target: https://circleci.com/gh/OpenZWave/python-openzwave :alt: Circle status +.. image:: https://ci.appveyor.com/api/projects/status/2ogl8tx7o3pqphc9?svg=true + :target: https://ci.appveyor.com/project/bibi21000/python-openzwave + :alt: Appveyor status + .. image:: https://img.shields.io/pypi/format/python_openzwave.svg :target: https://pypi.python.org/pypi/python_openzwave :alt: Pypi format @@ -61,14 +65,14 @@ python-openzwave 0.4.x is here !!! .. code-block:: bash - (venvX) pip install cython wheel six + (venvX) pip install cython wheel six pyserial (venvX) pip install 'Louie>=1.1' - on python 3 : .. code-block:: bash - (venvX) pip install cython wheel six + (venvX) pip install cython wheel six pyserial (venvX) pip install 'PyDispatcher>=2.0.5' - Choose your flavor : @@ -88,7 +92,7 @@ python-openzwave 0.4.x is here !!! .. code-block:: bash - (venvX) pip install python_openzwave --install-option="--flavor=git" --no-deps + (venvX) pip install python_openzwave --no-deps --install-option="--flavor=git" - You can update to the last version of openzwave using the git flavor : diff --git a/appveyor.yml b/appveyor.yml index 2355691f..0dfab890 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,9 @@ environment: + PYPI_USER: + secure: yna6KiH2GE3Ka1G5a3TlUQ== + PYPI_PASSWORD: + secure: UpISOsYyHdCzurReV6FcTA== + global: # SDK v7.0 MSVC Express 2008's SetEnv.cmd script will fail if the # /E:ON and /V:ON options are not enabled in the batch script intepreter @@ -17,26 +22,42 @@ environment: PYTHON_VERSION: "3.6.x" PYTHON_ARCH: "64" - - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013 + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 PYTHON: "C:\\Python27" PYTHON_VERSION: "2.7.x" PYTHON_ARCH: "32" - - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013 + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 PYTHON: "C:\\Python27-x64" PYTHON_VERSION: "2.7.x" PYTHON_ARCH: "64" - - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 PYTHON: "C:\\Python34" PYTHON_VERSION: "3.4.x" PYTHON_ARCH: "32" - - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 PYTHON: "C:\\Python34-x64" PYTHON_VERSION: "3.4.x" PYTHON_ARCH: "64" + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + PYTHON: "C:\\Python37" + PYTHON_VERSION: "3.7.x" + PYTHON_ARCH: "32" + + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + PYTHON: "C:\\Python37-x64" + PYTHON_VERSION: "3.7.x" + PYTHON_ARCH: "64" + +deploy: + - provider: Environment + name: production + on: + APPVEYOR_REPO_TAG: true + install: # If there is a newer build queued for the same PR, cancel this one. # The AppVeyor 'rollout builds' option is supposed to serve the same @@ -70,29 +91,28 @@ install: # Upgrade to the latest version of pip to avoid it displaying warnings # about it being out of date. - - "pip install --disable-pip-version-check --user --upgrade pip" + - "python -m pip install --disable-pip-version-check --user --upgrade pip" # Install the build dependencies of the project. If some dependencies contain # compiled extensions and are not provided as pre-built wheel packages, # pip will build them from source using the MSVC compiler matching the # target Python version and architecture # - "%CMD_IN_ENV% pip install Cython six" - - "pip install wheel" - - "pip install Cython six" - - "pip install nose" + - "python -m pip install wheel" + - "python -m pip install pyserial" + - "python -m pip install Cython six" + - "python -m pip install nose" + - "python -m pip install twine" - ps: Write-Host "PYTHON_VERSION $env:PYTHON_VERSION" - - - ps: if ($env:PYTHON_VERSION -eq "2.7.x") { ` - pip install Louie } ` - else { ` - pip install PyDispatcher } - + + - cmd: IF "%PYTHON_VERSION%" == "2.7.x" ( python -m pip install Louie ) ELSE ( python -m pip install PyDispatcher ) + - git clone git://github.com/OpenZWave/open-zwave.git C:\projects\python-openzwave\openzwave build_script: # Build the compiled extension - - "python pyozw_win.py" + # "python pyozw_win.py" - "python setup.py install --flavor=dev" test_script: @@ -100,20 +120,21 @@ test_script: - "pyozw_check" - "nosetests --verbose tests/lib/autobuild tests/api/autobuild" -#~ after_test: +after_test: # If tests are successful, create binary packages for the project. - - del C:\projects\python-openzwave\openzwave /s /q - - ps: "ls \"C:/projects/python-openzwave/\"" - - ps: "ls \"C:/projects/python-openzwave/openzwave/\"" - - python setup.py bdist_wheel --flavor=git + - python setup.py bdist_wheel --flavor=dev #~ - "python setup.py bdist_wininst" #~ - "%CMD_IN_ENV% python setup.py bdist_msi" - ps: "ls dist" artifacts: # Archive the generated packages in the ci.appveyor.com build report. - - path: dist\* - -#on_success: -# - TODO: upload the content of dist/*.whl to a public wheelhouse -# + - path: dist/* + name: windowswheels + +deploy_script: + # upload to pypi for Windows + - cmd: IF "%APPVEYOR_REPO_TAG%" == "true" (echo "Uploading wheels") + - cmd: IF "%APPVEYOR_REPO_TAG%" == "true" (set HOME=%USERPROFILE%) + - cmd: IF "%APPVEYOR_REPO_TAG%" == "true" (twine upload dist/*.whl --repository-url https://upload.pypi.org/legacy/ -u %PYPI_USER% -p %PYPI_PASSWORD%) + - cmd: IF "%APPVEYOR_REPO_TAG%" == "true" (echo "Finished Artifact Deployment" ) diff --git a/archives/open-zwave-master-0.4.10.zip b/archives/open-zwave-master-0.4.10.zip new file mode 100644 index 00000000..9b9898ad Binary files /dev/null and b/archives/open-zwave-master-0.4.10.zip differ diff --git a/archives/open-zwave-master-0.4.11.zip b/archives/open-zwave-master-0.4.11.zip new file mode 100644 index 00000000..2247bde9 Binary files /dev/null and b/archives/open-zwave-master-0.4.11.zip differ diff --git a/archives/open-zwave-master-0.4.14.zip b/archives/open-zwave-master-0.4.14.zip new file mode 100644 index 00000000..b84d0d8b Binary files /dev/null and b/archives/open-zwave-master-0.4.14.zip differ diff --git a/archives/open-zwave-master-0.4.15.zip b/archives/open-zwave-master-0.4.15.zip new file mode 100644 index 00000000..12e55244 Binary files /dev/null and b/archives/open-zwave-master-0.4.15.zip differ diff --git a/archives/open-zwave-master-0.4.16.zip b/archives/open-zwave-master-0.4.16.zip new file mode 100644 index 00000000..670b7f68 Binary files /dev/null and b/archives/open-zwave-master-0.4.16.zip differ diff --git a/archives/open-zwave-master-0.4.17.zip b/archives/open-zwave-master-0.4.17.zip new file mode 100644 index 00000000..ffa36699 Binary files /dev/null and b/archives/open-zwave-master-0.4.17.zip differ diff --git a/archives/open-zwave-master-0.4.18.zip b/archives/open-zwave-master-0.4.18.zip new file mode 100644 index 00000000..9897a92f Binary files /dev/null and b/archives/open-zwave-master-0.4.18.zip differ diff --git a/archives/open-zwave-master-0.4.19.zip b/archives/open-zwave-master-0.4.19.zip new file mode 100644 index 00000000..62b61c1d Binary files /dev/null and b/archives/open-zwave-master-0.4.19.zip differ diff --git a/archives/open-zwave-master-0.4.5.zip b/archives/open-zwave-master-0.4.5.zip new file mode 100644 index 00000000..c9a94777 Binary files /dev/null and b/archives/open-zwave-master-0.4.5.zip differ diff --git a/archives/open-zwave-master-0.4.6.zip b/archives/open-zwave-master-0.4.6.zip new file mode 100644 index 00000000..c26caf17 Binary files /dev/null and b/archives/open-zwave-master-0.4.6.zip differ diff --git a/archives/open-zwave-master-0.4.7.zip b/archives/open-zwave-master-0.4.7.zip new file mode 100644 index 00000000..10e0a163 Binary files /dev/null and b/archives/open-zwave-master-0.4.7.zip differ diff --git a/archives/open-zwave-master-0.4.8.zip b/archives/open-zwave-master-0.4.8.zip new file mode 100644 index 00000000..f5d3cb1e Binary files /dev/null and b/archives/open-zwave-master-0.4.8.zip differ diff --git a/archives/open-zwave-master-0.4.9.zip b/archives/open-zwave-master-0.4.9.zip new file mode 100644 index 00000000..f8899041 Binary files /dev/null and b/archives/open-zwave-master-0.4.9.zip differ diff --git a/archives/python_openzwave-0.4.10.zip b/archives/python_openzwave-0.4.10.zip new file mode 100644 index 00000000..7762b7ff Binary files /dev/null and b/archives/python_openzwave-0.4.10.zip differ diff --git a/archives/python_openzwave-0.4.11.zip b/archives/python_openzwave-0.4.11.zip new file mode 100644 index 00000000..9ab4b224 Binary files /dev/null and b/archives/python_openzwave-0.4.11.zip differ diff --git a/archives/python_openzwave-0.4.14.zip b/archives/python_openzwave-0.4.14.zip new file mode 100644 index 00000000..31798f3d Binary files /dev/null and b/archives/python_openzwave-0.4.14.zip differ diff --git a/archives/python_openzwave-0.4.15.zip b/archives/python_openzwave-0.4.15.zip new file mode 100644 index 00000000..d341a2e2 Binary files /dev/null and b/archives/python_openzwave-0.4.15.zip differ diff --git a/archives/python_openzwave-0.4.16.zip b/archives/python_openzwave-0.4.16.zip new file mode 100644 index 00000000..c08369f2 Binary files /dev/null and b/archives/python_openzwave-0.4.16.zip differ diff --git a/archives/python_openzwave-0.4.17.zip b/archives/python_openzwave-0.4.17.zip new file mode 100644 index 00000000..f1008c65 Binary files /dev/null and b/archives/python_openzwave-0.4.17.zip differ diff --git a/archives/python_openzwave-0.4.18.zip b/archives/python_openzwave-0.4.18.zip new file mode 100644 index 00000000..4dafdcfd Binary files /dev/null and b/archives/python_openzwave-0.4.18.zip differ diff --git a/archives/python_openzwave-0.4.19.zip b/archives/python_openzwave-0.4.19.zip new file mode 100644 index 00000000..0c9cafef Binary files /dev/null and b/archives/python_openzwave-0.4.19.zip differ diff --git a/archives/python_openzwave-0.4.5.zip b/archives/python_openzwave-0.4.5.zip new file mode 100644 index 00000000..db6317d6 Binary files /dev/null and b/archives/python_openzwave-0.4.5.zip differ diff --git a/archives/python_openzwave-0.4.6.zip b/archives/python_openzwave-0.4.6.zip new file mode 100644 index 00000000..9c6fa0f8 Binary files /dev/null and b/archives/python_openzwave-0.4.6.zip differ diff --git a/archives/python_openzwave-0.4.7.zip b/archives/python_openzwave-0.4.7.zip new file mode 100644 index 00000000..e0c43de7 Binary files /dev/null and b/archives/python_openzwave-0.4.7.zip differ diff --git a/archives/python_openzwave-0.4.8.zip b/archives/python_openzwave-0.4.8.zip new file mode 100644 index 00000000..26d47a4c Binary files /dev/null and b/archives/python_openzwave-0.4.8.zip differ diff --git a/archives/python_openzwave-0.4.9.zip b/archives/python_openzwave-0.4.9.zip new file mode 100644 index 00000000..51918e6a Binary files /dev/null and b/archives/python_openzwave-0.4.9.zip differ diff --git a/debian/changelog b/debian/changelog index f8f6f123..8744ed4c 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -python-openzwave (0.4.4) UNRELEASED; urgency=medium +python-openzwave (0.4.19) UNRELEASED; urgency=medium * Try to fix * Automatic release from upstream. Look at CHANGELOG.txt @@ -13,8 +13,23 @@ python-openzwave (0.4.4) UNRELEASED; urgency=medium * Automatic release from upstream. Look at CHANGELOG.txt * Automatic release from upstream. Look at CHANGELOG.txt * Automatic release from upstream. Look at CHANGELOG.txt + * Automatic release from upstream. Look at CHANGELOG.txt + * Automatic release from upstream. Look at CHANGELOG.txt + * Automatic release from upstream. Look at CHANGELOG.txt + * Automatic release from upstream. Look at CHANGELOG.txt + * Automatic release from upstream. Look at CHANGELOG.txt + * Automatic release from upstream. Look at CHANGELOG.txt + * Automatic release from upstream. Look at CHANGELOG.txt + * Automatic release from upstream. Look at CHANGELOG.txt + * Automatic release from upstream. Look at CHANGELOG.txt + * Automatic release from upstream. Look at CHANGELOG.txt + * Automatic release from upstream. Look at CHANGELOG.txt + * Automatic release from upstream. Look at CHANGELOG.txt + * Automatic release from upstream. Look at CHANGELOG.txt + * Automatic release from upstream. Look at CHANGELOG.txt + * Automatic release from upstream. Look at CHANGELOG.txt - -- bibi21000 Sat, 03 Feb 2018 20:04:54 +0100 + -- bibi21000 Wed, 20 Mar 2019 10:57:44 +0100 python-openzwave (0.3.0b8) UNRELEASED; urgency=medium diff --git a/docs/CHANGELOG.rst b/docs/CHANGELOG.rst index 0d299cda..ec9d1b02 100755 --- a/docs/CHANGELOG.rst +++ b/docs/CHANGELOG.rst @@ -4,12 +4,59 @@ Changelog ========= +python_openzwave 0.4.18.x: + * Fix python 2.7/appveyor + * Add serial port auto-detection + + +python_openzwave 0.4.17.x: + * Add wheels for Windows + + +python_openzwave 0.4.16.x: + * Fix appveyor build for windows + + +python_openzwave 0.4.15.x: + * Update embeded package + + +python_openzwave 0.4.14.x: + * Use Cython 0.28.6 + * Update embeded package + + +python_openzwave 0.4.12.x: + * Improve support Windows + * COMMAND_CLASS_ZWAVE_PLUS_INFO renamed to COMMAND_CLASS_ZWAVEPLUS_INFO + * Update thermostat + * Update embeded package + + +python_openzwave 0.4.11.x: + * Update embeded package + + +python_openzwave 0.4.10.x: + * Improve support Windows in pip + * Improve tests Windows + * Update contructors for scenes and groups + + +python_openzwave 0.4.9.x: + * Improve support Windows in pip + * Update tests + + +python_openzwave 0.4.6.x: + * First try to support Windows in pip + + python_openzwave 0.4.5.x: * Fix bug in node statistics and add test. * Update Makefile to build flavor dev * Update pyozw_check. * Update default flavor : check cython is here before choosing shared - * First try to support Windows in pip * Fix controller.update_ozw_config when directory isn't writable diff --git a/docs/INSTALL.rst b/docs/INSTALL.rst new file mode 100755 index 00000000..890e529c --- /dev/null +++ b/docs/INSTALL.rst @@ -0,0 +1,41 @@ +:orphan: + +==================================== +Installing python-openzwave from pip +==================================== + + +Flavors +======= + +Flavor embed +------------ + + +Flavor shared +------------- + + +Flavor git +---------- + + +Flavor ozwdev +------------- + + +Flavor ozwdev +------------- + + +Flavor dev +---------- + + +OS +== + +Windows +------- + + diff --git a/docs/README.rst b/docs/README.rst index 830221cd..c4ae7c44 100755 --- a/docs/README.rst +++ b/docs/README.rst @@ -65,14 +65,14 @@ python-openzwave 0.4.x is here !!! .. code-block:: bash - (venvX) pip install cython wheel six + (venvX) pip install cython wheel six pyserial (venvX) pip install 'Louie>=1.1' - on python 3 : .. code-block:: bash - (venvX) pip install cython wheel six + (venvX) pip install cython wheel six pyserial (venvX) pip install 'PyDispatcher>=2.0.5' - Choose your flavor : diff --git a/docs/index.rst b/docs/index.rst index c3e38beb..6cc2f303 100755 --- a/docs/index.rst +++ b/docs/index.rst @@ -7,9 +7,10 @@ Contents: :maxdepth: 3 The Readme. + Installation notes. The low level library ("pyx") to the ZWave network. The API. Map a ZWave Network in python objects. - How to submit a PR. + How to submit a PR. Changelog. diff --git a/pyozw_progressbar.py b/pyozw_progressbar.py new file mode 100644 index 00000000..7ea4d0ce --- /dev/null +++ b/pyozw_progressbar.py @@ -0,0 +1,159 @@ +import sys +import os +import time +import datetime +import io +import threading + +try: + PY3 = not unicode +except NameError: + PY3 = True + +TEMPLATE = ( + '\r' + '{prefix} ' + '{percent}% ' + '{count} ' + 'Elapsed: 0{elapsed} ' + 'Remaining: {remaining} ' + '{file_name}' +) + + +def remap(value, old_min=0, old_max=0, new_min=0, new_max=0): + old_range = old_max - old_min + new_range = new_max - new_min + + return ( + int((((value - old_min) * new_range) / old_range)) + new_min + ) + + +print_lock = threading.Lock() + + +class ProgressBar(object): + + def __init__(self): + self.stdout = sys.stdout + sys.stdout = self + self.files = [] + self.count = 0 + self.start = None + self.prefix = '' + self.last_line_len = 0 + self.file_position = 0 + + def flush(self): + pass + + def isatty(self): + return True + + def close(self): + if self.start is not None: + print_lock.acquire() + if self.files: + self.update(50, 100, file_name=self.files[-1]) + else: + self.update(50, 100, file_name='') + + self.stdout.write('\n\n') + self.stdout.flush() + print_lock.release() + + sys.stdout = self.stdout + + def write(self, line): + if PY3: + try: + line = line.decode("utf-8") + except AttributeError: + pass + + if str('Build openzwave') in line: + print_lock.acquire() + self.stdout.write('\n') + self.stdout.flush() + + # try: + # self.file_position = self.stdout.tell() + # except (io.UnsupportedOperation, WindowsError): + # pass + + self.prefix = 'Build OpenZWave' + self.start = time.time() + self.update(0, 0, file_name='') + print_lock.release() + + elif self.start is not None: + if str('/errorReport:queue') in line: + print_lock.acquire() + files = line.split('/errorReport:queue ')[1] + self.files = [ + os.path.split(f)[1] for f in files.split(' ') + ] + self.count = len(self.files) + print_lock.release() + + elif line.strip() in self.files: + print_lock.acquire() + self.files.remove(line.strip()) + count = remap( + self.count - len(self.files), + old_max=self.count, + new_max=50 + ) + percent = remap( + self.count - len(self.files), + old_max=self.count, + new_max=100 + ) + + self.update(count, percent, line.strip()) + if not self.files: + self.update(50, 100, file_name='') + print_lock.release() + + def update(self, count, percent, file_name): + current = time.time() + elapsed = current - self.start + + percent = str(percent) + percent = ' ' * (3 - len(percent)) + percent + + if count: + time_per_file = elapsed / (self.count - len(self.files)) + remaining = time_per_file * len(self.files) + remaining = '0' + str(datetime.timedelta(seconds=int(remaining))) + else: + remaining = '99:99:99' + + line = TEMPLATE.format( + prefix=self.prefix, + percent=percent, + count='#' * count + ' ' * (50 - count), + elapsed=str(datetime.timedelta(seconds=int(elapsed))), + remaining=remaining, + file_name=file_name + ) + + # try: + # self.stdout.seek(self.file_position) + # self.stdout.truncate() + # except (io.UnsupportedOperation, WindowsError): + # pass + + if self.last_line_len: + self.stdout.write('\r' + ' ' * self.last_line_len) + + self.stdout.write(line) + self.stdout.flush() + self.last_line_len = len(line) + + def __getattr__(self, item): + if item in self.__dict__: + return self.__dict__[item] + + return getattr(self.stdout, item) diff --git a/pyozw_setup.py b/pyozw_setup.py index f9d2d21d..b201840f 100644 --- a/pyozw_setup.py +++ b/pyozw_setup.py @@ -54,6 +54,11 @@ from pyozw_version import pyozw_version +try: + PY3 = not unicode +except NameError: + PY3 = True + LOCAL_OPENZWAVE = os.getenv('LOCAL_OPENZWAVE', 'openzwave') SETUP_DIR = os.path.dirname(os.path.abspath(__file__)) @@ -136,7 +141,7 @@ def system_context(self, ctx, static=False): if sys.platform.startswith("win"): from pyozw_win import get_system_context - get_system_context(ctx, self.os_options, openzwave=self.openzwave, static=static) + get_system_context(ctx, self.os_options, openzwave=os.path.abspath(self.openzwave), static=static) elif sys.platform.startswith("cygwin"): if static: @@ -148,8 +153,8 @@ def system_context(self, ctx, static=False): ctx['libraries'] += [ "openzwave" ] extra = pyozw_pkgconfig.cflags('libopenzwave') if extra != '': - for ssubstitute in ['/', '/value_classes/', '/platform/']: - ctx['extra_compile_args'] += [ extra.replace('//', ssubstitute) ] + for ssubstitute in ['', 'value_classes', 'platform']: + ctx['extra_compile_args'] += [ os.path.normpath(os.path.join(extra, ssubstitute)) ] elif sys.platform.startswith("darwin") : ctx['extra_link_args'] += [ "-framework", "CoreFoundation", "-framework", "IOKit" ] @@ -163,10 +168,11 @@ def system_context(self, ctx, static=False): ctx['libraries'] += [ "openzwave" ] extra = pyozw_pkgconfig.cflags('libopenzwave') if extra != '': - for ssubstitute in ['/', '/value_classes/', '/platform/']: - ctx['extra_compile_args'] += [ extra.replace('//', ssubstitute) ] + for ssubstitute in ['', 'value_classes', 'platform']: + ctx['extra_compile_args'] += [ os.path.normpath(os.path.join(extra, ssubstitute)) ] elif sys.platform.startswith("freebsd"): + os.environ["CPPFLAGS"] = "-Wno-unused-private-field" if static: ctx['libraries'] += [ "usb", "stdc++" ] ctx['extra_objects'] = [ "{0}/libopenzwave.a".format(self.openzwave) ] @@ -176,12 +182,12 @@ def system_context(self, ctx, static=False): ctx['libraries'] += [ "openzwave" ] extra = pyozw_pkgconfig.cflags('libopenzwave') if extra != '': - for ssubstitute in ['/', '/value_classes/', '/platform/']: - ctx['extra_compile_args'] += [ extra.replace('//', ssubstitute) ] + for ssubstitute in ['', 'value_classes', 'platform']: + ctx['extra_compile_args'] += [ os.path.normpath(os.path.join(extra, ssubstitute)) ] elif sys.platform.startswith("sunos"): if static: - ctx['libraries'] += [ "udev", "stdc++",'resolv' ] + ctx['libraries'] += [ "usb-1.0", "stdc++",'resolv' ] ctx['extra_objects'] = [ "{0}/libopenzwave.a".format(self.openzwave) ] ctx['include_dirs'] += [ "{0}/cpp/build/linux".format(self.openzwave) ] else: @@ -189,8 +195,8 @@ def system_context(self, ctx, static=False): ctx['libraries'] += [ "openzwave" ] extra = pyozw_pkgconfig.cflags('libopenzwave') if extra != '': - for ssubstitute in ['/', '/value_classes/', '/platform/']: - ctx['extra_compile_args'] += [ extra.replace('//', ssubstitute) ] + for ssubstitute in ['', 'value_classes', 'platform']: + ctx['extra_compile_args'] += [ os.path.normpath(os.path.join(extra, ssubstitute)) ] elif sys.platform.startswith("linux"): if static: @@ -202,8 +208,8 @@ def system_context(self, ctx, static=False): ctx['libraries'] += [ "openzwave" ] extra = pyozw_pkgconfig.cflags('libopenzwave') if extra != '': - for ssubstitute in ['/', '/value_classes/', '/platform/']: - ctx['extra_compile_args'] += [ extra.replace('//', ssubstitute) ] + for ssubstitute in ['', 'value_classes', 'platform']: + ctx['extra_compile_args'] += [ os.path.normpath(os.path.join(extra, ssubstitute)) ] else: # Unknown systemm @@ -248,10 +254,16 @@ def finalize_context(self, ctx): return ctx def install_requires(self): - return ['Cython'] + if sys.platform.startswith("win"): + return ['Cython'] + else: + return ['Cython==0.28.6'] def build_requires(self): - return ['Cython'] + if sys.platform.startswith("win"): + return ['Cython'] + else: + return ['Cython==0.28.6'] def build(self): if len(self.ctx['extra_objects']) == 1 and os.path.isfile(self.ctx['extra_objects'][0]): @@ -267,9 +279,16 @@ def build(self): io_q = Queue() def stream_watcher(identifier, stream): + # fixes subprocess output lag issue when using python 2.x - for line in stream: - io_q.put((identifier, line)) + if PY3: + dummy_return = b'' + else: + dummy_return = '' + + for line in iter(stream.readline, dummy_return): + if line: + io_q.put((identifier, line)) if not stream.closed: stream.close() @@ -289,44 +308,24 @@ def printer(): if identifier == 'STDERR': sys.stderr.write('{0}\n'.format(line)) log.error('{0}\n'.format(line)) + elif sys.platform.startswith("win"): + progress_bar.write(line) + + if sys.platform.startswith("win"): + progress_bar.close() if sys.platform.startswith("win"): - from pyozw_win import get_vsproject_upgrade_command, get_vsproject_build_command, get_vsproject_prebuild_command - if 'vsproject_upgrade' in self.os_options and self.os_options['vsproject_upgrade']: - log.info("Upgrade openzwave project ... be patient ...") - proc = Popen(get_vsproject_upgrade_command(self.os_options), - stdout=PIPE, stderr=PIPE, cwd='{0}'.format(self.os_options['vsproject'])) - Thread(target=stream_watcher, name='stdout-watcher', - args=('STDOUT', proc.stdout)).start() - Thread(target=stream_watcher, name='stderr-watcher', - args=('STDERR', proc.stderr)).start() - - tprinter = Thread(target=printer, name='printer') - tprinter.start() - while tprinter.is_alive(): - time.sleep(1) - tprinter.join() - #~ proc.wait() + from pyozw_progressbar import ProgressBar + from pyozw_win import get_clean_command, get_build_command + + cwd = os.path.split(self.os_options['solution_path'])[0] + build_command = get_build_command(**self.os_options) - if 'vsproject_prebuild' in self.os_options and self.os_options['vsproject_prebuild']: - log.info("Update configuration of openzwave project ... be patient ...") - proc = Popen(get_vsproject_prebuild_command(self.os_options), - stdout=PIPE, stderr=PIPE, cwd='{0}'.format(self.os_options['vsproject'])) - Thread(target=stream_watcher, name='stdout-watcher', - args=('STDOUT', proc.stdout)).start() - Thread(target=stream_watcher, name='stderr-watcher', - args=('STDERR', proc.stderr)).start() - - tprinter = Thread(target=printer, name='printer') - tprinter.start() - while tprinter.is_alive(): - time.sleep(1) - tprinter.join() - #~ proc.wait() log.info("Build openzwave ... be patient ...") - proc = Popen(get_vsproject_build_command(self.os_options), - stdout=PIPE, stderr=PIPE, cwd='{0}'.format(self.os_options['vsproject'])) + + progress_bar = ProgressBar() + proc = Popen(build_command, stdout=PIPE, stderr=PIPE, cwd=cwd) elif sys.platform.startswith("cygwin"): log.info("Build openzwave ... be patient ...") @@ -342,7 +341,8 @@ def printer(): elif sys.platform.startswith("sunos"): log.info("Build openzwave ... be patient ...") - proc = Popen('make', stdout=PIPE, stderr=PIPE, cwd='{0}'.format(self.openzwave)) + # fixed command issues to Popen + proc = Popen(['make', 'PREFIX=/opt/local'], stdout=PIPE, stderr=PIPE, cwd='{0}'.format(self.openzwave)) elif sys.platform.startswith("linux"): log.info("Build openzwave ... be patient ...") @@ -362,6 +362,7 @@ def printer(): while tprinter.is_alive(): time.sleep(1) tprinter.join() + return True def install_so(self): @@ -411,7 +412,7 @@ def printer(): proc = Popen([ 'gmake', 'install' ], stdout=PIPE, stderr=PIPE, cwd='{0}'.format(self.openzwave)) elif sys.platform.startswith("sunos"): - proc = Popen([ 'make', 'install' ], stdout=PIPE, stderr=PIPE, cwd='{0}'.format(self.openzwave)) + proc = Popen([ 'make', 'PREFIX=/opt/local', 'install' ], stdout=PIPE, stderr=PIPE, cwd='{0}'.format(self.openzwave)) elif sys.platform.startswith("linux"): proc = Popen([ 'make', 'install' ], stdout=PIPE, stderr=PIPE, cwd='{0}'.format(self.openzwave)) @@ -526,11 +527,15 @@ def printer(): log.error('{0}\n'.format(line)) proc = None if sys.platform.startswith("win"): - from pyozw_win import get_vsproject_devenv_clean_command - if 'devenv' in self.os_options and self.os_options['devenv'] is not None: - log.info("Clean openzwave project ... be patient ...") - proc = Popen(get_vsproject_devenv_clean_command(self.os_options), - stdout=PIPE, stderr=PIPE, cwd='{0}'.format(self.os_options['vsproject'])) + from pyozw_win import get_clean_command + clean_command = get_clean_command(**self.os_options) + log.info("Clean openzwave project ... be patient ...") + proc = Popen( + clean_command, + stdout=PIPE, + stderr=PIPE, + cwd=os.path.split(self.os_options['solution_path'])[0] + ) #~ proc.wait() #~ proc = Popen([ 'regsvr32', '-u', 'OpenZWave.dll' ], stdout=PIPE, stderr=PIPE, cwd='{0}'.format(os.path.abspath(self.openzwave))) #~ proc = Popen([ 'del', '/F', '/Q', '/S', '%SYSTEM32%\OpenZWave.dll' ], stdout=PIPE, stderr=PIPE, cwd='{0}'.format(os.path.abspath(self.openzwave))) @@ -545,7 +550,7 @@ def printer(): proc = Popen([ 'gmake', 'clean' ], stdout=PIPE, stderr=PIPE, cwd='{0}'.format(self.openzwave)) elif sys.platform.startswith("sunos"): - proc = Popen([ 'make', 'clean' ], stdout=PIPE, stderr=PIPE, cwd='{0}'.format(self.openzwave)) + proc = Popen([ 'make', 'PREFIX=/opt/local', 'clean' ], stdout=PIPE, stderr=PIPE, cwd='{0}'.format(self.openzwave)) elif sys.platform.startswith("linux"): proc = Popen([ 'make', 'clean' ], stdout=PIPE, stderr=PIPE, cwd='{0}'.format(self.openzwave)) @@ -589,17 +594,18 @@ def clean_all(self): def check_minimal_config(self): if sys.platform.startswith("win"): - log.info("Found MSBuild.exe : {0}".format(self.os_options['msbuild'])) - log.info("Found devenv.exe : {0}".format(self.os_options['devenv'])) + log.info("Found MSBuild.exe : {0}".format(self.os_options['msbuild_path'])) log.info("Found arch : {0}".format(self.os_options['arch'])) - log.info("Found build configuration : {0}".format(self.os_options['buildconf'])) - log.info("Found Visual Studio project : {0}".format(self.os_options['vsproject'])) - log.info("Found build path : {0}".format(self.os_options['vsproject_build'])) + log.info("Found build configuration : {0}".format(self.os_options['build_type'])) + log.info("Found Visual Studio project : {0}".format(self.os_options['solution_path'])) + log.info("Found build path : {0}".format(self.os_options['build_path'])) + log.info("Found cython : {0}".format(find_executable("cython"))) else: log.info("Found g++ : {0}".format(find_executable("g++"))) log.info("Found gcc : {0}".format(find_executable("gcc"))) log.info("Found make : {0}".format(find_executable("make"))) log.info("Found gmake : {0}".format(find_executable("gmake"))) + log.info("Found cython : {0}".format(find_executable("cython"))) exe = find_executable("pkg-config") log.info("Found pkg-config : {0}".format(exe)) if exe is not None: @@ -686,10 +692,18 @@ def __init__(self, **args): def get_context(self): opzw_dir = LOCAL_OPENZWAVE if LOCAL_OPENZWAVE is None: - return None + if sys.platform.startswith("win"): + from pyozw_win import get_openzwave + get_openzwave('openzwave') + else: + return None + if not os.path.isdir(opzw_dir): - log.error("Can't find {0}".format(opzw_dir)) - return None + if sys.platform.startswith("win"): + from pyozw_win import get_openzwave + get_openzwave(opzw_dir) + else: + return None self.openzwave = opzw_dir ctx = self.cython_context() if ctx is None: @@ -773,7 +787,6 @@ def __init__(self, **args): def get_openzwave(self, url='https://codeload.github.com/OpenZWave/open-zwave/zip/Dev'): return Template.get_openzwave(self, url) - class OzwdevSharedTemplate(GitSharedTemplate): def get_openzwave(self, url='https://codeload.github.com/OpenZWave/open-zwave/zip/Dev'): @@ -943,12 +956,14 @@ def parse_template(sysargv): tmpl.cleanozw = True log.info('sysargv', sysargv) print('sysargv', sysargv) + log.info("Found SETUP_DIR : {0}".format(SETUP_DIR)) + print("Found SETUP_DIR : {0}".format(SETUP_DIR)) return tmpl current_template = parse_template(sys.argv) def install_requires(): - pkgs = ['six'] + pkgs = ['six', 'pyserial'] if (sys.version_info > (3, 0)): pkgs.append('PyDispatcher>=2.0.5') else: @@ -984,7 +999,7 @@ def run(self): _bdist_egg.run(self) class build_openzwave(setuptools.Command): - description = 'download an build openzwave' + description = 'download and build openzwave' user_options = [ ('openzwave-dir=', None, diff --git a/pyozw_version.py b/pyozw_version.py index 088ca341..4b4d3e8b 100644 --- a/pyozw_version.py +++ b/pyozw_version.py @@ -21,7 +21,7 @@ along with python-openzwave. If not, see http://www.gnu.org/licenses. """ -pyozw_version = '0.4.4' +pyozw_version = '0.4.19' if "-" in pyozw_version: pyozw_version_short = pyozw_version.split("-") else: diff --git a/pyozw_win.py b/pyozw_win.py index 793dc366..3f052ace 100644 --- a/pyozw_win.py +++ b/pyozw_win.py @@ -22,481 +22,781 @@ """ -import sys, os -import fnmatch +import sys +import os import platform +import shutil +from pyozw_version import pyozw_version -VC9 = 'VC9' -VC10 = 'VC10' -VC14 = 'VC14' - -def get_win_config( debug=False ): - """Retrieve needed tools to build extension - Depend of python version - See https://wiki.python.org/moin/WindowsCompilers - """ - if sys.version_info >= (2,6) and sys.version_info < (3,3): - return VC9 - elif sys.version_info >= (3,3) and sys.version_info < (3,5): - return VC10 - elif sys.version_info >= (3,5): - return VC14 - -def find_all_build_tools(name, paths): - """Search for name recursively in paths - """ - result = [] - for path in paths: - for root, dirs, files in os.walk(path): - if name in files: - result.append(os.path.join(root, name)) - return result - -def find_msbuild_tools( options, debug=False ): - """Find MSBuild.exe - """ - win_config = get_win_config(debug=debug) - if win_config == VC14: - if 'devenv' in options and '2015' in options['devenv']: - vs_path = [ - 'c:\\Program Files (x86)\\MSBuild\\14.0', - 'c:\\Program Files (x86)\\Microsoft Visual Studio\\2015', - 'c:\\Program Files (x86)\\MSBuild\\15.0', - 'c:\\Program Files (x86)\\Microsoft Visual Studio\\2017', - ] +try: + _winreg = __import__('_winreg') +except ImportError: + _winreg = __import__('winreg') + + +from subprocess import Popen, PIPE + +# this is simply to show that you can build using only VS2017 as a requirement. +VS2017_VCVARSALL = r'"C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat"' + +WIN64 = '64' in platform.machine() +PYTHON64 = platform.architecture()[0] == '64bit' and WIN64 +ARCH = 'x64' if PYTHON64 else 'x86' + + +try: + PY3 = not unicode +except NameError: + PY3 = True + +TOOLSETS = { + 15.0: ['v141', '15.0'], # vs2017 + 14.0: ['v140', '14.0'], # vs2015 + 10.0: ['v100', '4.0'], # vs2010 + 4.0: ['v90', '4.0'], # vs2008 +} + + +def setup_build_env_2017(): + proc = Popen( + VS2017_VCVARSALL + ' ' + ARCH + ' && set', + shell=True, + stdout=PIPE, + stderr=PIPE + ) + + test_env = {} + for line in proc.stdout: + if PY3: + line = line.decode("utf-8") + + if '=' in line: + key, value = line.split('=', 1) + test_env[key.strip()] = value.strip() + + for key, value in list(test_env.items()): + if str(os.environ.get(key, None)) != value: + os.environ[key] = value + + os.environ['DISTUTILS_USE_SDK'] = '1' + + +# comment this line to run normally. +setup_build_env_2017() + + +def _get_reg_value(path, key): + d = _read_reg_values(path) + if key in d: + return d[key] + return '' + + +def _read_reg_keys(key): + try: + handle = _winreg.OpenKeyEx( + _winreg.HKEY_LOCAL_MACHINE, + 'SOFTWARE\\Wow6432Node\\Microsoft\\' + key + ) + except _winreg.error: + return [] + res = [] + + for i in range(_winreg.QueryInfoKey(handle)[0]): + res += [_winreg.EnumKey(handle, i)] + + return res + + +def _read_reg_values(key): + try: + handle = _winreg.OpenKeyEx( + _winreg.HKEY_LOCAL_MACHINE, + 'SOFTWARE\\Wow6432Node\\Microsoft\\' + key + ) + except _winreg.error: + return {} + res = {} + for i in range(_winreg.QueryInfoKey(handle)[1]): + name, value, _ = _winreg.EnumValue(handle, i) + res[_convert_mbcs(name)] = _convert_mbcs(value) + + return res + + +def _convert_mbcs(s): + dec = getattr(s, "decode", None) + if dec is not None: + try: + s = dec("mbcs") + except UnicodeError: + pass + return s + + +def get_environment(): + from setuptools.msvc import ( + msvc9_query_vcvarsall, + EnvironmentInfo, + msvc14_get_vc_env + ) + + py_version = sys.version_info[:2] + + if py_version >= (3, 5): + env = msvc14_get_vc_env(ARCH) + msbuild_version = 14.0 + env_info = EnvironmentInfo(ARCH) + msbuild_path = _find_file( + 'MSBuild.exe', + env_info.MSBuild[0] + )[0] + + sdks = ('10.0', '8.1', '8.1A', '8.0', '8.0A') + solution_dest = 'vs2015' + + elif (3, 5) > py_version >= (3, 3): + env = msvc9_query_vcvarsall(10.0, ARCH) + msbuild_version = 4.0 + msbuild_path = _get_reg_value( + 'MSBuild\\4.0', + 'MSBuildOverrideTasksPath' + ) + + if msbuild_path: + msbuild_path = _find_file( + 'MSBuild.exe', + msbuild_path + )[0] + + sdks = ('7.1', '7.0A') + solution_dest = 'vs2010' + + elif (3, 3) > py_version >= (2, 6): + env = msvc9_query_vcvarsall(9.0, ARCH) + msbuild_version = 4.0 + msbuild_path = _get_reg_value( + 'MSBuild\\4.0', + 'MSBuildOverrideTasksPath' + ) + + if msbuild_path: + msbuild_path = _find_file( + 'MSBuild.exe', + msbuild_path + )[0] + + sdks = ('6.1', '6.1A', '6.0A') + solution_dest = 'vs2008' + + else: + raise RuntimeError( + 'This library does not support python versions < 2.6' + ) + + for sdk in sdks: + sdk_version = _get_reg_value( + 'Microsoft SDKs\\Windows\\v' + sdk, + 'ProductVersion' + ) + if sdk_version: + sdk_installation_folder = _get_reg_value( + 'Microsoft SDKs\\Windows\\v' + sdk, + 'InstallationFolder' + ) + target_platform = sdk_version + os.environ['WindowsSdkDir'] = sdk_installation_folder + break + else: + raise RuntimeError('Unable to locate suitable SDK %s' % (sdks,)) + + platform_toolset, tools_version = TOOLSETS[msbuild_version] + + return ( + env, + msbuild_version, + msbuild_path, + sdk_installation_folder, + target_platform, + platform_toolset, + tools_version, + solution_dest + ) + + +def _find_file(file_name, path): + res = [] + + for root, dirs, files in os.walk(path): + if ( + ((PYTHON64 and 'amd64' in root) or 'amd64' not in root) and + file_name in files + ): + res.append(os.path.join(root, file_name)) + return res + + +def setup_build_environment(openzwave, build_type): + if 'DISTUTILS_USE_SDK' in os.environ: + target_platform = os.environ['WINDOWSSDKVERSION'].replace('\\', '') + + if 'VS150COMNTOOLS' in os.environ: + msbuild_version = 15.0 + solution_dest = 'vs2017' + + elif 'VS140COMNTOOLS' in os.environ: + msbuild_version = 14.0 + solution_dest = 'vs2015' else: - vs_path = [ - 'c:\\Program Files (x86)\\MSBuild\\15.0', - 'c:\\Program Files (x86)\\Microsoft Visual Studio\\2017', - 'c:\\Program Files (x86)\\MSBuild\\14.0', - 'c:\\Program Files (x86)\\Microsoft Visual Studio\\2015', - ] - if debug: - print("Check for MSBuild.exe in %s" %vs_path) - all_msbuild = find_all_build_tools("MSBuild.exe", vs_path) - if debug: - print("Found MSBuild.exe in %s" %all_msbuild) - if options['arch'] == 'x64': - msbuild2 = [name for name in all_msbuild if 'amd64' in name] - if options['arch'] == 'Win32': - msbuild2 = [name for name in all_msbuild if not 'amd64' in name] - if debug: - print("Found MSBuild.exe in %s" %msbuild2) - if len(msbuild2) == 0: - raise RuntimeError("Can't find MSBuild.exe for arch %s in %s looked in %s"%(options['arch'], all_msbuild, vs_path)) - options['msbuild'] = msbuild2[0] - - elif win_config == VC10: - vs_path = [ - 'c:\\Program Files (x86)\\Microsoft Visual Studio 10.0', - 'c:\\Program Files (x86)\\Microsoft Visual Studio 11.0', - 'c:\\Program Files (x86)\\MSBuild', - ] - if debug: - print("Check for MSBuild.exe in %s" %vs_path) - all_msbuild = find_all_build_tools("MSBuild.exe", vs_path) - if debug: - print("Found MSBuild.exe in %s" %all_msbuild) - if options['arch'] == 'x64': - msbuild2 = [name for name in all_msbuild if 'amd64' in name] - if options['arch'] == 'Win32': - msbuild2 = [name for name in all_msbuild if not 'amd64' in name] - if debug: - print("Found MSBuild.exe in %s" %msbuild2) - if len(msbuild2) == 0: - raise RuntimeError("Can't find MSBuild.exe for arch %s in %s looked in %s"%(options['arch'], all_msbuild, vs_path)) - options['msbuild'] = msbuild2[0] - - elif win_config == VC9: - vs_path = [ - 'c:\\Program Files (x86)\\Microsoft Visual Studio 9.0', - 'c:\\Program Files (x86)\\MSBuild', - ] - if debug: - print("Check for MSBuild.exe in %s" %vs_path) - all_msbuild = find_all_build_tools("MSBuild.exe", vs_path) - if debug: - print("Found MSBuild.exe in %s" %all_msbuild) - if options['arch'] == 'x64': - msbuild2 = [name for name in all_msbuild if 'amd64' in name] - if options['arch'] == 'Win32': - msbuild2 = [name for name in all_msbuild if not 'amd64' in name] - if debug: - print("Found MSBuild.exe in %s" %msbuild2) - if len(msbuild2) == 0: - raise RuntimeError("Can't find MSBuild.exe for arch %s in %s looked in %s"%(options['arch'], all_msbuild, vs_path)) - options['msbuild'] = msbuild2[0] - return 'msbuild' in options - -def find_devenv_tools( options, debug=False ): - """Find devenv.exe - """ - win_config = get_win_config(debug=debug) - if win_config == VC14: - vs_path = [ - 'c:\\Program Files (x86)\\Microsoft Visual Studio\\2015', - 'c:\\Program Files (x86)\\Microsoft Visual Studio\\2017', - ] - if debug: - print("Check for devenv in %s" %vs_path) - all_msbuild = find_all_build_tools("devenv.exe", vs_path) - if debug: - print("Found devenv in %s" %all_msbuild) - if len(all_msbuild) == 0: - raise RuntimeError("Can't find devenv in %s looked in %s"%(all_msbuild, vs_path)) - options['devenv'] = all_msbuild[0] - - elif win_config == VC10: - vs_path = [ - 'c:\\Program Files (x86)\\Microsoft Visual Studio 10.0', - 'c:\\Program Files (x86)\\Microsoft Visual Studio 11.0', - ] - if debug: - print("Check for devenv.exe in %s" %vs_path) - all_msbuild = find_all_build_tools("devenv.exe", vs_path) - if debug: - print("Found devenv.exe in %s" %all_msbuild) - if len(all_msbuild) == 0: - raise RuntimeError("Can't find devenv.exe in %s looked in %s"%( all_msbuild, vs_path )) - options['devenv'] = all_msbuild[0] - - elif win_config == VC9: - #~ vs_path = ['c:\\Program Files (x86)\\Microsoft Visual Studio 9.0', - #~ ] - #~ if debug: - #~ print("Check for devenv.exe in %s" %vs_path) - #~ all_msbuild = find_all_build_tools("devenv.exe", vs_path) - #~ if debug: - #~ print("Found devenv.exe in %s" %all_msbuild) - #~ if len(all_msbuild) == 0: - #~ raise RuntimeError("Can't find devenv.exe in %s looked in %s"%( all_msbuild, vs_path )) - #~ options['devenv'] = all_msbuild[0] - options['devenv'] = None - return 'devenv' in options - -def get_vs_project( options, openzwave='openzwave', debug=False ): - """Retrieve needed tools to build extension - Depend of python version - See https://wiki.python.org/moin/WindowsCompilers - """ - win_config = get_win_config(debug=debug) - if win_config == VC14: - if '2015' in options['devenv']: - options['vsproject'] = os.path.join(openzwave,'cpp','build','windows','vs2015') - elif '2017' in options['devenv']: - options['vsproject'] = os.path.join(openzwave,'cpp','build','windows','vs2017') - if not ( 'vsproject' in options ): - raise RuntimeError("Can't find devenv.exe for VS2017 / VS2015") - import shutil - if os.path.isdir(options['vsproject']): - shutil.rmtree(options['vsproject']) - shutil.copytree(os.path.join(openzwave,'cpp','build','windows','vs2010'), options['vsproject']) - options['vsproject_upgrade'] = True - options['vsproject_prebuild'] = False - elif win_config == VC10: - options['vsproject'] = os.path.join(openzwave,'cpp','build','windows','vs2010') - options['vsproject_upgrade'] = False - options['vsproject_prebuild'] = False - elif win_config == VC9: - options['vsproject'] = os.path.join(openzwave,'cpp','build','windows','vs2008') - options['vsproject_upgrade'] = False - options['vsproject_prebuild'] = False - if options['arch'] == "x64" : - options['vsproject_build'] = os.path.join(options['vsproject'], options['arch'], options['buildconf']) - update_vs_project( options, debug=debug ) + raise RuntimeError + + msbuild_path = _find_file('MSBuild.exe', os.environ['VSINSTALLDIR'])[0] + platform_toolset, tools_version = TOOLSETS[msbuild_version] + sdk_installation_folder = os.environ['WINDOWSSDKVERBINPATH'] + os.environ['MSSDK'] = sdk_installation_folder + else: - options['vsproject_build'] = os.path.join(options['vsproject'], options['buildconf']) - return 'vsproject' in options - -def update_vs_project( options, openzwave="openzwave", debug=False, update_version=False ): - """Retrieve needed tools to build extension - Depend of python version - See https://wiki.python.org/moin/WindowsCompilers - """ - from xml.etree import ElementTree - import copy - - ElementTree.register_namespace('', "http://schemas.microsoft.com/developer/msbuild/2003") - if update_version: - bversion="4.0" - toolset='v100' - if '2015' in options['devenv'] or ('14.0' in options['msbuild'] and not('Visual Studio' in options['msbuild']) ): - bversion="14.0" - toolset='v140' - elif '2017' in options['devenv'] or ('15.0' in options['msbuild'] and not('Visual Studio' in options['msbuild']) ): - bversion="15.0" - toolset='v141' - - tree = ElementTree.parse(os.path.join(options['vsproject'], 'OpenZWave.vcxproj'), parser=None) - root = tree.getroot() - - if update_version: - root.set('ToolsVersion', bversion) - - for p in root.findall("{http://schemas.microsoft.com/developer/msbuild/2003}ItemGroup"): - if 'Label' in p.attrib and p.attrib['Label'] == 'ProjectConfigurations': - prjconfs = p - - newconfs = [] - for p in prjconfs: - dupe = copy.deepcopy(p) #copy node - dupe.set('Include', dupe.attrib['Include'].replace('Win32', 'x64')) - dupe.find('{http://schemas.microsoft.com/developer/msbuild/2003}Platform').text = 'x64' - newconfs.append(dupe) #insert the new node - for new in newconfs: - prjconfs.append(new) - - newconfs = [] - prjconfs = [ p for p in root.findall("{http://schemas.microsoft.com/developer/msbuild/2003}PropertyGroup") - if p.get('Label') == 'Configuration'] - for p in prjconfs: - plat = p.find('{http://schemas.microsoft.com/developer/msbuild/2003}PlatformToolset') - if update_version: - if plat is not None: - plat.text = toolset - else: - newKid = ElementTree.Element('{http://schemas.microsoft.com/developer/msbuild/2003}PlatformToolset') - newKid.text = toolset - p.append(newKid) - dupe = copy.deepcopy(p) #copy node - dupe.set('Condition', dupe.attrib['Condition'].replace('Win32', 'x64')) - newconfs.append(dupe) #insert the new node - for new in newconfs: - root.append(new) - - newconfs = [] - prjconfs = [ p for p in root.findall("{http://schemas.microsoft.com/developer/msbuild/2003}ImportGroup") - if p.get('Condition') is not None ] - for p in prjconfs: - dupe = copy.deepcopy(p) #copy node - dupe.set('Condition', dupe.attrib['Condition'].replace('Win32', 'x64')) - newconfs.append(dupe) #insert the new node - for new in newconfs: - root.append(new) - - newconfs = [] - prjconfs = [ p for p in root.findall("{http://schemas.microsoft.com/developer/msbuild/2003}ItemDefinitionGroup") - if p.get('Condition') is not None ] - for p in prjconfs: - dupe = copy.deepcopy(p) #copy node - dupe.set('Condition', dupe.attrib['Condition'].replace('Win32', 'x64')) - newconfs.append(dupe) #insert the new node - for new in newconfs: - root.append(new) - - newconfs = [] - prj = [ p for p in root.findall("{http://schemas.microsoft.com/developer/msbuild/2003}PropertyGroup") - if len(p.findall("{http://schemas.microsoft.com/developer/msbuild/2003}_ProjectFileVersion"))>0 ] - prjconfs = [ p for p in prj[0] if p.get('Condition') is not None ] - for p in prjconfs: - dupe = copy.deepcopy(p) #copy node - dupe.set('Condition', dupe.attrib['Condition'].replace('Win32', 'x64')) - newconfs.append(dupe) #insert the new node - for new in newconfs: - prj[0].append(new) - - tree.write(os.path.join(options['vsproject'], 'OpenZWave.vcxproj'),xml_declaration=False) - - with open(os.path.join(options['vsproject'], 'OpenZWave.sln'), 'r') as f: - sln = f.read() - - targets = [ - ('Debug|Win32','Debug|x64'), - ('DebugDLL|Win32','DebugDLL|x64'), - ('Release|Win32','Release|x64'), - ('ReleaseDLL|Win32','ReleaseDLL|x64'), - ] - for target in targets: - sln = sln.replace( - '%s = %s'%(target[0], target[0]), - '%s = %s\n\t\t%s = %s'%(target[0], target[0], target[1], target[1]) + ( + env, + msbuild_version, + msbuild_path, + sdk_installation_folder, + target_platform, + platform_toolset, + tools_version, + solution_dest + ) = get_environment() + + if 'WINDOWSSDKVERBINPATH' in env: + sdk_installation_folder = env['WINDOWSSDKVERBINPATH'] + + env['MSSDK'] = sdk_installation_folder + env['DISTUTILS_USE_SDK'] = '1' + + for key, value in env.items(): + os.environ[key] = value + + if 'VS150COMNTOOLS' in os.environ and msbuild_version == 14.0: + platform_toolset = 'v141' + tools_version = '15.0' + msbuild_version = 15.0 + solution_dest = 'vs2017' + + if 'WINDOWSSDKLIBVERSION' in os.environ: + target_platform = ( + os.environ['WINDOWSSDKLIBVERSION'].replace('\\', '') + ) + + if not msbuild_path: + raise RuntimeError( + 'Unable to locate MSBuild to compile OpenZWave' ) - targets = [ - ('{497F9828-DEC2-4C80-B9E0-AD066CCB587C}.Debug|Win32.ActiveCfg = Debug|Win32', '{497F9828-DEC2-4C80-B9E0-AD066CCB587C}.Debug|x64.ActiveCfg = Debug|x64'), - ('{497F9828-DEC2-4C80-B9E0-AD066CCB587C}.Debug|Win32.Build.0 = Debug|Win32', '{497F9828-DEC2-4C80-B9E0-AD066CCB587C}.Debug|x64.Build.0 = Debug|x64'), - ('{497F9828-DEC2-4C80-B9E0-AD066CCB587C}.DebugDLL|Win32.ActiveCfg = DebugDLL|Win32', '{497F9828-DEC2-4C80-B9E0-AD066CCB587C}.DebugDLL|x64.ActiveCfg = DebugDLL|x64'), - ('{497F9828-DEC2-4C80-B9E0-AD066CCB587C}.DebugDLL|Win32.Build.0 = DebugDLL|Win32', '{497F9828-DEC2-4C80-B9E0-AD066CCB587C}.DebugDLL|x64.Build.0 = DebugDLL|x64'), - ('{497F9828-DEC2-4C80-B9E0-AD066CCB587C}.Release|Win32.ActiveCfg = Release|Win32', '{497F9828-DEC2-4C80-B9E0-AD066CCB587C}.Release|x64.ActiveCfg = Release|x64'), - ('{497F9828-DEC2-4C80-B9E0-AD066CCB587C}.Release|Win32.Build.0 = Release|Win32', '{497F9828-DEC2-4C80-B9E0-AD066CCB587C}.Release|x64.Build.0 = Release|x64'), - ('{497F9828-DEC2-4C80-B9E0-AD066CCB587C}.ReleaseDLL|Win32.ActiveCfg = ReleaseDLL|Win32', '{497F9828-DEC2-4C80-B9E0-AD066CCB587C}.ReleaseDLL|x64.ActiveCfg = ReleaseDLL|x64'), - ('{497F9828-DEC2-4C80-B9E0-AD066CCB587C}.ReleaseDLL|Win32.Build.0 = ReleaseDLL|Win32', '{497F9828-DEC2-4C80-B9E0-AD066CCB587C}.ReleaseDLL|x64.Build.0 = ReleaseDLL|x64'), - ] - for target in targets: - sln = sln.replace( - '%s'%(target[0]), - '%s\n\t\t%s'%(target[0], target[1]) + project_base_path = os.path.abspath( + os.path.join( + openzwave, + 'cpp', + 'build', + 'windows' ) + ) - with open(os.path.join(options['vsproject'], 'OpenZWave.sln'), 'w') as f: - f.write(sln) - if debug: - print("OpenZWave project for visual studio updated" ) + project_path = os.path.join(project_base_path, solution_dest) + + if PYTHON64: + build_path = os.path.join(project_path, 'x64', build_type) + else: + build_path = os.path.join(project_path, build_type) + + if not os.path.exists(project_path): + shutil.copytree( + os.path.join(project_base_path, 'vs2010'), + project_path + ) + + print('Updating VS solution please wait.') + + if update_vs_project( + os.path.join(project_path, 'OpenZWave.vcxproj'), + tools_version, + platform_toolset, + target_platform + ): + with open(os.path.join(project_path, 'OpenZWave.sln'), 'r') as f: + sln = str(f.read()).replace('\r', '') + + if GLOBAL_SELECTION_TEMPLATE not in sln: + sln = sln.replace( + GLOBAL_SELECTION_KEY, + GLOBAL_SELECTION_TEMPLATE + ) + + with open(os.path.join(project_path, 'OpenZWave.sln'), 'w') as f: + f.write(sln) + + solution_path = os.path.join(project_path, 'OpenZWave.sln') + + return ( + solution_path, + build_path, + msbuild_path, + msbuild_version, + target_platform, + platform_toolset, + tools_version, + sdk_installation_folder + ) + + +def update_vs_project(path, tools_version, platform_toolset, target_platform): + from xml.etree import ElementTree + + vcxproj_xmlns = 'http://schemas.microsoft.com/developer/msbuild/2003' + ElementTree.register_namespace('', vcxproj_xmlns) + + with open(path, 'r') as f: + vcxproj = f.read() + + # the original xml file contains some characters that the xml parser + # does not like, these are non human readable characters and they do not + # need to exist. So we remove them. + for char in (187, 191, 239): + vcxproj = vcxproj.replace(chr(char), '') + + root = ElementTree.fromstring(vcxproj) + + vcxproj_xmlns = '{' + vcxproj_xmlns + '}' + + # there are only 3 things that need to get changed once the solution has + # been fully updated. the tools version, the platform teeolset + # and the windows target platform. if a cached version of openzwave is used + # there is no need to create a whole new solution. so what we do is we set + # an attribute in the root of the xml to inform us if the file has been + # upgraded already. + + root.attrib['ToolsVersion'] = tools_version + + for node in root.findall(vcxproj_xmlns + 'PropertyGroup'): + if ( + 'Label' in node.attrib and + node.attrib['Label'] == 'Configuration' + ): + for sub_node in node: + if ( + sub_node.tag.replace(vcxproj_xmlns, '') == + 'PlatformToolset' + ): + sub_node.text = platform_toolset + break + else: + sub_node = ElementTree.Element('PlatformToolset') + sub_node.text = platform_toolset + node.append(sub_node) + + for node in root.findall(vcxproj_xmlns + 'PropertyGroup'): + if 'Label' in node.attrib and node.attrib['Label'] == 'Globals': + for sub_node in node: + if ( + sub_node.tag.replace(vcxproj_xmlns, '') == + 'WindowsTargetPlatformVersion' + ): + sub_node.text = target_platform + break + else: + sub_node = ElementTree.Element('WindowsTargetPlatformVersion') + sub_node.text = target_platform + node.append(sub_node) + + # this function is the core of upgrading the solution. It burrows down + # into a node through each layer and makes a copy. this copy gets modified + # to become an x64 version. the copy gets returned and then added to the + # xml file + + def iter_node(old_node): + new_node = ElementTree.Element(old_node.tag) + if old_node.text is not None: + new_node.text = old_node.text.replace('Win32', 'x64') + + for key, value in old_node.attrib.items(): + new_node.attrib[key] = value.replace('Win32', 'x64') + for old_sub_node in old_node: + new_node.append(iter_node(old_sub_node)) + return new_node + + # here is the testing to se if the file has been updated before. + if 'PythonOpenZWave' not in root.attrib: + update = True + root.attrib['PythonOpenZWave'] = 'True' + i = 0 + + for node in root[:]: + tag = node.tag.replace(vcxproj_xmlns, '') + + if ( + tag == 'ItemGroup' and + 'Label' in node.attrib and + node.attrib['Label'] == 'ProjectConfigurations' + ): + for sub_item in node[:]: + node.append(iter_node(sub_item)) + + if ( + tag == 'PropertyGroup' and + 'Label' in node.attrib and + node.attrib['Label'] == 'Configuration' + ): + root.insert(i, iter_node(node)) + i += 1 + + if ( + tag == 'ImportGroup' and + 'Label' in node.attrib and + node.attrib['Label'] == 'PropertySheets' + ): + root.insert(i, iter_node(node)) + i += 1 + + if ( + tag == 'PropertyGroup' and + not node.attrib.keys() + ): + j = 0 + for sub_item in node[:]: + if ( + sub_item.tag.replace(vcxproj_xmlns, '') != + '_ProjectFileVersion' + ): + node.insert(j, iter_node(sub_item)) + j += 1 + + if tag == 'ItemDefinitionGroup': + root.insert(i, iter_node(node)) + i += 1 + i += 1 + else: + update = False + + with open(path, 'w')as f: + f.write(xml_tostring(root, vcxproj_xmlns)) + + # we return if the file was updated or not. this is a flag that tells up + # if we need to update the sln file. + return update -def get_system_context( ctx, options, openzwave="openzwave", static=False, debug=False ): +# this is a custom xml writer. it recursively iterates through an +# ElementTree object creating a formatted string that is as close as i can +# get it to what Visual Studio creates. I did this for consistency as well +# as ease of bug testing + +def xml_tostring(node, xmlns, indent=''): + tag = node.tag.replace(xmlns, '') + no_text = node.text is None or not node.text.strip() + + if indent: + output = '' + else: + output = '\n' + if xmlns: + node.attrib['xmlns'] = xmlns.replace('{', '').replace('}', '') + + if no_text and not list(node) and not node.attrib.keys(): + output += '{0}<{1} />\n'.format(indent, tag) + else: + output += '{0}<{1}'.format(indent, tag) + + for key in sorted(node.attrib.keys()): + output += ' {0}="{1}"'.format(key, str(node.attrib[key])) + + if not list(node) and no_text: + output += ' />\n' + elif not no_text and not list(node): + output += '>{0}\n'.format(node.text, tag) + elif list(node) and no_text: + output += '>\n' + for item in node: + output += xml_tostring(item, xmlns, indent + ' ') + output += '{0}\n'.format(indent, tag) + else: + output += '>\n {0}{1}\n'.format(indent, node.text) + for item in node: + output += xml_tostring(item, xmlns, indent + ' ') + output += '{0}\n'.format(indent, tag) + return output + + +# because we no longer use devenv in favor of msbuild there are only 2 commands +# needed. +# one for clean and the other to build +def get_clean_command(msbuild_path, solution_path, build_type, arch, **_): + clean_template = ( + '"{msbuild_path}" ' + '"{solution_path}" ' + '/property:Configuration={build_type} ' + '/property:Platform={arch} ' + '/t:Clean ' + ) + clean_command = clean_template.format( + msbuild_path=msbuild_path, + solution_path=solution_path, + build_type=build_type, + arch=arch + ) + + return clean_command + + +def get_build_command(msbuild_path, solution_path, build_type, arch, **_): + build_template = ( + '"{msbuild_path}" ' + '"{solution_path}" ' + '/property:Configuration={build_type} ' + '/property:Platform={arch} ' + '/t:Build' + ) + + build_command = build_template.format( + msbuild_path=msbuild_path, + solution_path=solution_path, + build_type=build_type, + arch=arch + ) + + return build_command + + +def get_system_context( + ctx, + options, + openzwave="openzwave", + static=False, + debug=False +): + if debug: print("get_system_context for windows") + # one feature i added is building a debugging version, this is only going + # to happen if sys.executable ends with _d which identifies that the python + # interpreter is a debugging build. + if static: - options['buildconf'] = 'Release' + if os.path.splitext(sys.executable)[0].endswith('_d'): + options['build_type'] = 'Debug' + ctx['define_macros'] += [('_DEBUG', 1)] + ctx['libraries'] += ["setupapi", "msvcrtd", "ws2_32", "dnsapi"] + else: + options['build_type'] = 'Release' + ctx['libraries'] += ["setupapi", "msvcrt", "ws2_32", "dnsapi"] else: - options['buildconf'] = 'ReleaseDLL' + if os.path.splitext(sys.executable)[0].endswith('_d'): + options['build_type'] = 'DebugDLL' + ctx['define_macros'] += [('_DEBUG', 1)] + ctx['libraries'] += ["setupapi", "msvcrtd", "ws2_32", "dnsapi"] + else: + options['build_type'] = 'ReleaseDLL' + ctx['libraries'] += ["setupapi", "msvcrt", "ws2_32", "dnsapi"] - if 'arch' not in options: + if PYTHON64: + options['arch'] = "x64" + else: options['arch'] = 'Win32' - python_arch,_ = platform.architecture() - if python_arch == "64bit": - options['arch'] = "x64" - if debug: - print("Found arch %s" %options['arch']) - if 'devenv' not in options: - find_devenv_tools( options, debug=debug ) - if 'msbuild' not in options: - find_msbuild_tools( options, debug=debug ) - if 'vsproject' not in options: - get_vs_project( options, openzwave=openzwave, debug=debug ) + ( + solution_path, + build_path, + msbuild_path, + msbuild_version, + target_platform, + platform_toolset, + tools_version, + sdk_installation_folder + ) = setup_build_environment(openzwave, options['build_type']) + + options['msbuild_path'] = msbuild_path + options['solution_path'] = solution_path + options['build_path'] = build_path + options['msbuild_version'] = msbuild_version + options['target_platform'] = target_platform + options['platform_toolset'] = platform_toolset + options['tools_version'] = tools_version + options['sdk_installation_folder'] = sdk_installation_folder if debug: - print("Found options %s" %options) - - ctx['libraries'] += [ "setupapi", "msvcrt", "ws2_32", "dnsapi" ] + print('Platform: %s' % target_platform) + print('Platform architecture %s' % ARCH) + print('Platform toolset: %s' % platform_toolset) + print('MSBuild path: %s' % msbuild_path) + print('MSBuild version: %0.1f' % msbuild_version) + print('MSBuild tools version: %s' % tools_version) + print('SDK installation path: %s' % sdk_installation_folder) + print("Found options %s" % options) + + cpp_path = os.path.join(openzwave, 'cpp') + src_path = os.path.join(cpp_path, 'src') if static: - ctx['extra_objects'] = [ "{0}/OpenZWave.lib".format(options['vsproject_build']) ] - ctx['include_dirs'] += [ "{0}/cpp/build/windows".format(openzwave), - "src-lib/libopenzwave", - "{0}".format(options['vsproject_build']), - ] + ctx['extra_objects'] = [os.path.join(build_path, 'OpenZWave.lib')] + + ctx['include_dirs'] += [ + src_path, + os.path.join(src_path, 'value_classes'), + os.path.join(src_path, 'platform'), + os.path.join(cpp_path, 'build', 'windows'), + build_path, + ] else: - ctx['libraries'] += [ "OpenZWave" ] + ctx['libraries'] += ["OpenZWave"] + ctx['extra_compile_args'] += [ - "{0}/cpp/src".format(openzwave), - "{0}/cpp/src/value_classes".format(openzwave), - "{0}/cpp/src/platform".format(openzwave) ] + src_path, + os.path.join(src_path, 'value_classes'), + os.path.join(src_path, 'platform'), + ] -def get_vsproject_upgrade_command( options, debug=False ): - if debug: - print("get_vsproject_upgrade_command" ) - return [ '%s'%options['devenv'], - 'OpenZWave.sln', - '/upgrade', - ] + ctx['define_macros'] += [ + ('CYTHON_FAST_PYCCALL', 1), + ('_MT', 1), + ('_DLL', 1) + ] -def get_vsproject_prebuild_command( options, debug=False ): - if debug: - print("get_vsproject_prebuild_command" ) - return [ '"%s"'%options['devenv'], - '/updateconfiguration', - '/out', - 'LogUpdateConfiguration.htm', - ] - -def get_vsproject_build_command( options, debug=False ): - if debug: - print("get_vsproject_build_command" ) - print( - '%s'%options['msbuild'], - 'OpenZWave.sln', - '/t:Rebuild', - '/p:Configuration={0}'.format(options['buildconf']), - '/p:Platform={0}'.format(options['arch']) - ) - return [ '%s'%options['msbuild'], - 'OpenZWave.sln', - '/t:Rebuild', - '/p:Configuration={0}'.format(options['buildconf']), - '/p:Platform={0}'.format(options['arch']) - ] - -def get_vsproject_devenv_build_command( options, debug=False ): - if debug: - print("get_vsproject_build_command" ) - print( - options['devenv'], - 'OpenZWave.sln', - '/Rebuild', - '"{0}|{1}"'.format(options['buildconf'],options['arch']) - ) - return [ '%s'%options['devenv'], - 'OpenZWave.sln', - '/Rebuild', - '"{0}|{1}"'.format(options['buildconf'],options['arch']) - ] -def get_vsproject_devenv_clean_command( options, debug=False ): - if debug: - print("get_vsproject_devenv_clean_command" ) - print( - options['devenv'], - 'OpenZWave.sln', - '/Clean', - '"{0}|{1}"'.format(options['buildconf'],options['arch']) - ) - return [ '%s'%options['devenv'], - 'OpenZWave.sln', - '/Clean', - '"{0}|{1}"'.format(options['buildconf'],options['arch']) - ] +GLOBAL_SELECTION_TEMPLATE = ''' Debug|x64 = Debug|x64 + DebugDLL|x64 = DebugDLL|x64 + Release|x64 = Release|x64 + ReleaseDLL|x64 = ReleaseDLL|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {497F9828-DEC2-4C80-B9E0-AD066CCB587C}.Debug|x64.ActiveCfg = Debug|x64 + {497F9828-DEC2-4C80-B9E0-AD066CCB587C}.Debug|x64.Build.0 = Debug|x64 + {497F9828-DEC2-4C80-B9E0-AD066CCB587C}.DebugDLL|x64.ActiveCfg = DebugDLL|x64 + {497F9828-DEC2-4C80-B9E0-AD066CCB587C}.DebugDLL|x64.Build.0 = DebugDLL|x64 + {497F9828-DEC2-4C80-B9E0-AD066CCB587C}.Release|x64.ActiveCfg = Release|x64 + {497F9828-DEC2-4C80-B9E0-AD066CCB587C}.Release|x64.Build.0 = Release|x64 + {497F9828-DEC2-4C80-B9E0-AD066CCB587C}.ReleaseDLL|x64.ActiveCfg = ReleaseDLL|x64 + {497F9828-DEC2-4C80-B9E0-AD066CCB587C}.ReleaseDLL|x64.Build.0 = ReleaseDLL|x64''' + + +GLOBAL_SELECTION_KEY = ''' EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution''' + + +def get_openzwave(opzw_dir): + url = 'https://codeload.github.com/OpenZWave/open-zwave/zip/master' + + from io import BytesIO + try: + from urllib2 import urlopen + except ImportError: + from urllib.request import urlopen + + import zipfile + + base_path = os.path.dirname(__file__) + + print('Downloading openzwave...') + + req = urlopen(url) + dest_file = BytesIO(req.read()) + dest_file.seek(0) + + zip_ref = zipfile.ZipFile(dest_file, 'r') + zip_ref.extractall(base_path) + zip_ref.close() + dest_file.close() + + os.rename( + os.path.join(base_path, zip_ref.namelist()[0]), + opzw_dir + ) + if __name__ == '__main__': - from subprocess import Popen, PIPE, call + from subprocess import Popen, PIPE + from setuptools import setup + from distutils.extension import Extension + print("Start pyozw_win") - ctx = { "name": "libopenzwave", - "sources": [ ], - "include_dirs": [ ], - "libraries": [ ], - "extra_objects": [ ], - "extra_compile_args": [ ], - "extra_link_args": [ ], - "language": "c++", - } + + ctx = dict( + name='libopenzwave', + sources=['src-lib\\libopenzwave\\libopenzwave.pyx'], + include_dirs=['src-lib\\libopenzwave'], + define_macros=[ + ('PY_LIB_VERSION', pyozw_version), + ('PY_SSIZE_T_CLEAN', 1), + ('PY_LIB_FLAVOR', 'dev'), + ('PY_LIB_BACKEND', 'cython') + ], + libraries=[], + extra_objects=[], + extra_compile_args=[], + extra_link_args=[], + language='c++' + ) + + ozw_path = os.path.abspath('openzwave') + + if not os.path.exists(ozw_path): + get_openzwave('openzwave') + options = dict() - get_system_context( ctx, options, openzwave="openzwave", static=True, debug=True ) - - print(options['vsproject']) - print(' '.join(get_vsproject_devenv_clean_command( options ))) - #~ os.system( ' '.join(get_vsproject_devenv_clean_command( options )) ) - proc = Popen(get_vsproject_devenv_clean_command( options, debug=True ), - shell=True, - stdout=PIPE, - stderr=PIPE, - cwd='{0}'.format(options['vsproject'])) - for line in proc.stdout: - print(line) - errcode = proc.returncode - for line in proc.stderr: - print(line) - - #~ os.system( ' '.join(get_vsproject_upgrade_command( options )) ) - proc = Popen(get_vsproject_upgrade_command( options, debug=True ), - shell=True, - stdout=PIPE, - stderr=PIPE, - cwd='{0}'.format(options['vsproject'])) - for line in proc.stdout: - print(line) - errcode = proc.returncode - for line in proc.stderr: - print(line) - - #~ proc = Popen(get_vsproject_prebuild_command( options, debug=True ), cwd='{0}'.format(options['vsproject'])) - #~ proc.wait() - - #~ proc = call(get_vsproject_devenv_build_command( options, debug=True ), cwd='{0}'.format(options['vsproject'])) - #~ proc = call(get_vsproject_build_command( options, debug=True ), cwd='{0}'.format(options['vsproject'])) - #~ os.system( ' '.join(get_vsproject_build_command( options )) ) - proc = Popen(get_vsproject_build_command( options, debug=True ), - shell=True, - stdout=PIPE, - stderr=PIPE, - cwd='{0}'.format(options['vsproject'])) - for line in proc.stdout: - print(line) - errcode = proc.returncode - for line in proc.stderr: - print(line) - - print('Library built in %s using compiler %s for arch %s' % (options['vsproject_build'], options['msbuild'], options['arch'])) + + get_system_context( + ctx, + options, + openzwave=ozw_path, + static=True, + debug=True + ) + + clean = get_clean_command(**options) + build = get_build_command(**options) + + def run(command): + print('Running command:', command) + proc = Popen( + command, + shell=True, + stdout=PIPE, + stderr=PIPE, + cwd=os.path.split(options['solution_path'])[0], + ) + + if PY3: + dummy_return = b'' + else: + dummy_return = '' + + for line in iter(proc.stdout.readline, dummy_return): + if line and PY3: + sys.stdout.write(line.decode("utf-8")) + elif line: + sys.stdout.write(line) + + errcode = proc.returncode + print('\n\nerrcode', errcode, '\n\n') + + for line in iter(proc.stderr.readline, dummy_return): + if line and PY3: + sys.stdout.write(line.decode("utf-8")) + elif line: + sys.stdout.write(line) + + # run(clean) + # run(build) + + print( + 'Library built in %s using compiler %s for arch %s' % + (options['build_path'], options['msbuild_path'], options['arch']) + ) + + setup( + script_args=['build_ext'], + version=pyozw_version, + name='libopenzwave', + description='libopenzwave', + verbose=1, + ext_modules=[Extension(**ctx)], + ) diff --git a/src-api/openzwave/command.py b/src-api/openzwave/command.py index a9d7d34f..4b6d330c 100755 --- a/src-api/openzwave/command.py +++ b/src-api/openzwave/command.py @@ -835,7 +835,7 @@ def set_thermostat_heating(self, value): """ logger.debug(u"set_thermostat_heating value:%s", value) for v in self.get_thermostats(): - if self.values[v].command_class == 0x43 and self.values[v].label == 'Heating 1': + if self.values[v].command_class == 0x43 and self.values[v].label in ('Heating 1', 'Heating'): self.values[v].data = value return True return False @@ -852,7 +852,7 @@ def set_thermostat_cooling(self, value): """ logger.debug(u"set_thermostat_cooling value:%s", value) for v in self.get_thermostats(): - if self.values[v].command_class == 0x43 and self.values[v].label == 'Cooling 1': + if self.values[v].command_class == 0x43 and self.values[v].label in ('Cooling 1', 'Cooling'): self.values[v].data = value return True return False diff --git a/src-api/openzwave/controller.py b/src-api/openzwave/controller.py index 38f97dfd..745740a9 100755 --- a/src-api/openzwave/controller.py +++ b/src-api/openzwave/controller.py @@ -367,7 +367,7 @@ def python_library_config_version(self): tversion = "Original %s" % self.library_version fversion = os.path.join(self.library_config_path, 'pyozw_config.version') if os.path.isfile(fversion): - with open(fversion, 'r') as f: + with open(fversion, 'r') as f: val = f.read() tversion = "Git %s" % val return tversion @@ -1378,7 +1378,7 @@ def update_ozw_config(self): shutil.rmtree(dest) except Exception: pass - + if os.path.isdir(self.library_config_path): #Try to remove old config try: @@ -1392,32 +1392,18 @@ def update_ozw_config(self): logger.exception("Can't copy to %s", self.library_config_path) try: - with open(os.path.join(self.library_config_path, 'pyozw_config.version'), 'w') as f: - f.write(time.strftime("%Y-%m-%d %H:%M")) + with open(os.path.join(self.library_config_path, 'pyozw_config.version'), 'w') as f: + f.write(time.strftime("%Y-%m-%d %H:%M")) except Exception: logger.exception("Can't update %s", os.path.join(self.library_config_path, 'pyozw_config.version')) - shutil.rmtree(dest) + try: + with open(os.path.join(self.library_config_path, '__init__.py'), 'a') as f: + f.write("#This file is part of **python-openzwave** project https://github.com/OpenZWave/python-openzwave.") + except Exception: + logger.exception("Can't create %s", os.path.join(self.library_config_path, '__init__.py')) + + shutil.rmtree(dest) - def update_ozw_config(self): - """ - Update the openzwave config from github. - Not available for shared flavor as we don't want to update the config of the precompiled config. - """ - if self.python_library_flavor in ['shared']: - logger.warning(u"Can't update_ozw_config for this flavor (%s)."%self.python_library_flavor) - return - logger.info(u'Update_ozw_config from github.') - dest = tempfile.mkdtemp() - dest_file = os.path.join(dest, 'open-zwave.zip') - req = urlopen('https://codeload.github.com/OpenZWave/open-zwave/zip/master') - with open(dest_file, 'wb') as f: - f.write(req.read()) - zip_ref = zipfile.ZipFile(dest_file, 'r') - zip_ref.extractall(dest) - zip_ref.close() - os.system("cp -rf %s %s"%(os.path.join(dest, 'open-zwave-master', 'config'), self.library_config_path)) - with open(os.path.join(self.library_config_path, 'pyozw_config.version'), 'w') as f: - f.write(time.strftime("%Y-%m-%d %H:%M")) diff --git a/src-api/openzwave/group.py b/src-api/openzwave/group.py index 177c3992..22c96d62 100755 --- a/src-api/openzwave/group.py +++ b/src-api/openzwave/group.py @@ -44,7 +44,7 @@ class ZWaveGroup(ZWaveObject): Also used to retrieve information about the library, ... """ - def __init__(self, group_index, network=None, node_id=None): + def __init__(self, group_index, network, node_id): """ Initialize driver object diff --git a/src-api/openzwave/option.py b/src-api/openzwave/option.py index 74571f46..7fc68990 100755 --- a/src-api/openzwave/option.py +++ b/src-api/openzwave/option.py @@ -43,6 +43,32 @@ def emit(self, record): logger = logging.getLogger('openzwave') logger.addHandler(NullHandler()) + +VENDOR_IDS = ('0658',) + + +def _get_z_stick(): + try: + import serial.tools.list_ports + except ImportError: + return None + + for port in serial.tools.list_ports.comports(include_links=False): + if port.vid is None: + continue + if port.product is not None and 'Zigbee' in port.product: + continue + if port.interface is not None and 'Zigbee' in port.interface: + continue + if port.description is not None and 'Zigbee' in port.description: + continue + + for vid in VENDOR_IDS: + if vid.upper() == hex(port.vid)[2:].upper().zfill(4): + return port.device + return None + + class ZWaveOption(libopenzwave.PyOptions): """ Represents a Zwave option used to start the manager. @@ -52,7 +78,7 @@ def __init__(self, device=None, config_path=None, user_path=None, cmd_line=None) """ Create an option object and check that parameters are valid. - :param device: The device to use + :param device: The device to use or None for auto detection (pyserial needs to be installed for auto detection). :type device: str :param config_path: The openzwave config directory. If None, try to configure automatically. :type config_path: str @@ -62,7 +88,13 @@ def __init__(self, device=None, config_path=None, user_path=None, cmd_line=None) :type cmd_line: str """ + if device is None: + device = _get_z_stick() + if platform_system() == 'Windows': + if device and not device.startswith('\\\\.\\'): + device = '\\\\.\\' + device + self._device = device else: #For linux diff --git a/src-api/openzwave/scene.py b/src-api/openzwave/scene.py index 2d5a722e..5911c9b8 100755 --- a/src-api/openzwave/scene.py +++ b/src-api/openzwave/scene.py @@ -42,7 +42,7 @@ class ZWaveScene(ZWaveObject): Represents a single scene within the Z-Wave Network """ - def __init__(self, scene_id, network=None): + def __init__(self, scene_id, network): """ Initialize zwave scene diff --git a/src-lib/libopenzwave/libopenzwave.pyx b/src-lib/libopenzwave/libopenzwave.pyx index c35bbe09..2753a7d5 100644 --- a/src-lib/libopenzwave/libopenzwave.pyx +++ b/src-lib/libopenzwave/libopenzwave.pyx @@ -1079,7 +1079,7 @@ sleeping) have been polled, an "AllNodesQueried" notification is sent. 0x56: 'COMMAND_CLASS_CRC_16_ENCAP', 0x5A: 'COMMAND_CLASS_DEVICE_RESET_LOCALLY', 0x5B: 'COMMAND_CLASS_CENTRAL_SCENE', - 0x5E: 'COMMAND_CLASS_ZWAVE_PLUS_INFO', + 0x5E: 'COMMAND_CLASS_ZWAVEPLUS_INFO', 0x60: 'COMMAND_CLASS_MULTI_INSTANCE/CHANNEL', 0x61: 'COMMAND_CLASS_DISPLAY', 0x62: 'COMMAND_CLASS_DOOR_LOCK', diff --git a/src-manager/pyozwman/ozwsh_widgets.py b/src-manager/pyozwman/ozwsh_widgets.py index e2d611cf..9c892614 100755 --- a/src-manager/pyozwman/ozwsh_widgets.py +++ b/src-manager/pyozwman/ozwsh_widgets.py @@ -1342,7 +1342,7 @@ def add(self, param, value): def set(self, param, value): values = self.window.network.nodes[self.node_id].values try: - param = long(param) + param = int(param) except: ok = False for val in values: @@ -1375,7 +1375,7 @@ def set(self, param, value): def poll(self, param, value): values = self.window.network.nodes[self.node_id].values try: - param = long(param) + param = int(param) except: ok = False for val in values: @@ -1975,7 +1975,7 @@ def cd(self, directory): def delete(self, value): valueid = None try: - valueid = long(value) + valueid = int(value) except: ok = False try: diff --git a/src-python_openzwave/python_openzwave/scripts/pyozw_check.py b/src-python_openzwave/python_openzwave/scripts/pyozw_check.py index 36baa0a0..0d888a2f 100644 --- a/src-python_openzwave/python_openzwave/scripts/pyozw_check.py +++ b/src-python_openzwave/python_openzwave/scripts/pyozw_check.py @@ -65,7 +65,7 @@ def imports(args): time.sleep(0.5) print("Try to import openzwave (API)") import openzwave - + elif args.output == 'raw': import libopenzwave from libopenzwave import PyLogLevels @@ -96,7 +96,7 @@ def zwcallback(zwargs): if notify_type == "DriverReady": global home_id home_id = zwargs['homeId'] - + #~ print("Received {0} : {1}".format(notify_type,libopenzwave.PyNotifications[notify_type].doc)) if args.output == 'txt': print("Received {0}".format(notify_type)) @@ -255,11 +255,11 @@ def list_nodes(args): print("Stop network") network.stop() print("Exit") - + def pyozw_parser(): parser = argparse.ArgumentParser(description='Run python_openzwave basics checks.') parser.add_argument('-o', '--output', action='store', help='The format (txt, raw, ...)', choices=['txt', 'raw'], default='txt') - parser.add_argument('-d', '--device', action='store', help='The device port', default='/dev/ttyUSB0') + parser.add_argument('-d', '--device', action='store', help='The device port', default=None) parser.add_argument('-m', '--imports', action='store_true', help='Import all libs', default=True) parser.add_argument('-i', '--init_device', action='store_true', help='Intialize the device', default=False) parser.add_argument('-l', '--list_nodes', action='store_true', help='List the nodes on zwave network', default=False) @@ -278,7 +278,7 @@ def main(): list_nodes(args) elif args.imports: imports(args) - + if __name__ == '__main__': main() diff --git a/src-python_openzwave/python_openzwave/scripts/pyozw_shell.py b/src-python_openzwave/python_openzwave/scripts/pyozw_shell.py index fd365333..b6b67fb7 100755 --- a/src-python_openzwave/python_openzwave/scripts/pyozw_shell.py +++ b/src-python_openzwave/python_openzwave/scripts/pyozw_shell.py @@ -49,7 +49,7 @@ def main(): '-d', '--device', dest='device', type="str", - default="/dev/ttyUSB0", + default=None, help="The path to your ZWave device") parser.add_option( diff --git a/tests/api/common.py b/tests/api/common.py index c4a8c32d..b771cf64 100644 --- a/tests/api/common.py +++ b/tests/api/common.py @@ -89,7 +89,7 @@ def setUp(self): self.ctrl_command_result = None self.ctrl_command_signal = None self.wait_for_network_state(self.network.STATE_AWAKED, 1) - time.sleep(1.0) + time.sleep(2.0) self.wait_for_queue() self.active_nodes = {} for node in self.network.nodes: diff --git a/tests/api/test_command.py b/tests/api/test_command.py index 609187c8..264fe0d3 100644 --- a/tests/api/test_command.py +++ b/tests/api/test_command.py @@ -62,7 +62,8 @@ def test_010_battery_item(self): for node in self.active_nodes: for val in self.active_nodes[node].get_battery_levels() : ran = True - self.assertTrue(isinstance(self.active_nodes[node].get_battery_level(val), integer_types)) + self.assertTrue(isinstance(self.active_nodes[node].get_battery_level(val), + six.integer_types)) if ran == False : self.skipTest("No battery found") diff --git a/tests/api/test_controller_command.py b/tests/api/test_controller_command.py index 047fca19..0e5c3b51 100644 --- a/tests/api/test_controller_command.py +++ b/tests/api/test_controller_command.py @@ -64,9 +64,10 @@ def tearDownClass(self): super(TestControllerCommand, self).tearDownClass() def setUp(self): - self.wait_for_network_state(self.network.STATE_READY, 1) - self.wait_for_queue() - self.ctrl_state_result = None + # ~ self.wait_for_network_state(self.network.STATE_READY, 1) + # ~ self.wait_for_queue() + # ~ self.ctrl_state_result = None + TestApi.setUp(self) dispatcher.connect(self.ctrl_message, ZWaveNetwork.SIGNAL_CONTROLLER_COMMAND) dispatcher.connect(self.ctrl_waiting, ZWaveNetwork.SIGNAL_CONTROLLER_WAITING) time.sleep(2.0) @@ -106,9 +107,10 @@ def test_005_request_controller_status(self): def test_010_command_send_node_information_nodes(self): self.ctrl_state_result = None - node_ids = [ k for k in self.network.nodes.keys() if k != self.network.controller.node_id ] + node_ids = [ k for k in self.active_nodes.keys() if k != self.network.controller.node_id ] for node_id in node_ids: - node_id = max(self.network.nodes.keys()) + # ~ node_id = max(self.network.nodes.keys()) + # ~ node_id = self.active_nodes.keys()[1] ret = self.network.controller.send_node_information(node_id) self.assertTrue(ret) current = None @@ -120,7 +122,9 @@ def test_010_command_send_node_information_nodes(self): break else: time.sleep(1.0) + print(self.ctrl_command_signal) self.assertEqual(current, self.network.controller.STATE_COMPLETED) + self.assertEqual(self.ctrl_command_signal['node_id'], node_id) def test_015_command_send_node_information_controller(self): self.ctrl_state_result = None @@ -140,7 +144,8 @@ def test_015_command_send_node_information_controller(self): def test_020_command_request_node_neighbor_update_nodes(self): self.wipTest() self.ctrl_state_result = None - node_ids = [ k for k in self.network.nodes.keys() if k != self.network.controller.node_id ] + + node_ids = [ k for k in self.active_nodes.keys() if k != self.network.controller.node_id ] for node_id in node_ids: ret = self.network.controller.request_node_neighbor_update(node_id) self.assertTrue(ret) @@ -173,7 +178,7 @@ def test_025_command_request_node_neighbor_update_controller(self): def test_030_command_request_network_update_nodes(self): self.ctrl_state_result = None - node_ids = [ k for k in self.network.nodes.keys() if k != self.network.controller.node_id ] + node_ids = [ k for k in self.active_nodes.keys() if k != self.network.controller.node_id ] for node_id in node_ids: node_id = max(self.network.nodes.keys()) ret = self.network.controller.request_network_update(node_id) @@ -206,7 +211,7 @@ def test_035_command_request_network_update_controller(self): def test_040_command_delete_all_return_routes_nodes(self): self.ctrl_state_result = None - node_ids = [ k for k in self.network.nodes.keys() if k != self.network.controller.node_id ] + node_ids = [ k for k in self.active_nodes.keys() if k != self.network.controller.node_id ] for node_id in node_ids: node_id = max(self.network.nodes.keys()) ret = self.network.controller.delete_all_return_routes(node_id) @@ -239,7 +244,7 @@ def test_045_command_delete_all_return_routes_controller(self): def test_050_command_assign_return_route_nodes(self): self.ctrl_state_result = None - node_ids = [ k for k in self.network.nodes.keys() if k != self.network.controller.node_id ] + node_ids = [ k for k in self.active_nodes.keys() if k != self.network.controller.node_id ] for node_id in node_ids: node_id = max(self.network.nodes.keys()) ret = self.network.controller.assign_return_route(node_id) @@ -272,7 +277,7 @@ def test_055_command_assign_return_route_controller(self): def test_060_command_has_node_failed_nodes(self): self.ctrl_state_result = None - node_ids = [ k for k in self.network.nodes.keys() if k != self.network.controller.node_id ] + node_ids = [ k for k in self.active_nodes.keys() if k != self.network.controller.node_id ] for node_id in node_ids: node_id = max(self.network.nodes.keys()) ret = self.network.controller.has_node_failed(node_id) @@ -287,10 +292,11 @@ def test_060_command_has_node_failed_nodes(self): else: time.sleep(1.0) self.assertEqual(current, self.network.controller.STATE_NODEOK) + self.assertEqual(self.ctrl_command_signal['node_id'], node_id) def test_070_command_remove_failed_node_nodes(self): self.ctrl_state_result = None - node_ids = [ k for k in self.network.nodes.keys() if k != self.network.controller.node_id ] + node_ids = [ k for k in self.active_nodes.keys() if k != self.network.controller.node_id ] for node_id in node_ids: node_id = max(self.network.nodes.keys()) ret = self.network.controller.remove_failed_node(node_id) @@ -308,7 +314,7 @@ def test_070_command_remove_failed_node_nodes(self): def test_080_command_replace_failed_node_nodes(self): self.ctrl_state_result = None - node_ids = [ k for k in self.network.nodes.keys() if k != self.network.controller.node_id ] + node_ids = [ k for k in self.active_nodes.keys() if k != self.network.controller.node_id ] for node_id in node_ids: node_id = max(self.network.nodes.keys()) ret = self.network.controller.replace_failed_node(node_id) diff --git a/tests/api/test_switch.py b/tests/api/test_switch.py index 5b277fe7..697bfff4 100644 --- a/tests/api/test_switch.py +++ b/tests/api/test_switch.py @@ -26,7 +26,9 @@ """ -import os, shutil +import os +import shutil +import sys import time import unittest from pprint import pprint diff --git a/tests/common.py b/tests/common.py index ba570d71..badec123 100644 --- a/tests/common.py +++ b/tests/common.py @@ -25,12 +25,9 @@ """ -#The common sleep dealy to wait for network -#We wait 1*SLEEP for network.STATE_AWAKED -#After that we wait 1*SLEEP for network.STATE_READY -SLEEP = 45 - -import sys, os +import os +import shutil +import sys import time import unittest import threading @@ -39,6 +36,11 @@ #~ import bson import six +#The common sleep dealy to wait for network +#We wait 1*SLEEP for network.STATE_AWAKED +#After that we wait 1*SLEEP for network.STATE_READY +SLEEP = 45 + class SetEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, set): @@ -65,7 +67,7 @@ class TestPyZWave(unittest.TestCase): """ device = "/dev/ttyUSB0" ozwlog = "Debug" - ozwout = False + ozwout = True pylog = logging.DEBUG userpath = ".tests_user_path" diff --git a/tests/manager/autobuild/test_manager.py b/tests/manager/autobuild/test_manager.py index 5c0c6d0b..d8568016 100644 --- a/tests/manager/autobuild/test_manager.py +++ b/tests/manager/autobuild/test_manager.py @@ -32,6 +32,7 @@ import sys import time import logging +import unittest from tests.manager.common import TestManager diff --git a/tests/web/autobuild/test_web.py b/tests/web/autobuild/test_web.py index 2e33446f..52488258 100644 --- a/tests/web/autobuild/test_web.py +++ b/tests/web/autobuild/test_web.py @@ -32,6 +32,7 @@ import sys import time import logging +import unittest #~ from tests.web.common import FlaskTestBase diff --git a/tests/web/test_server.py b/tests/web/test_server.py index 6134f941..b5833cfe 100644 --- a/tests/web/test_server.py +++ b/tests/web/test_server.py @@ -32,6 +32,7 @@ import sys import time import logging +import unittest #~ from flask.ext.socketio import SocketIO, emit, join_room, leave_room, close_room, disconnect #~ from flask.ext.socketio.test_client import SocketIOTestClient