2019-04-24 14:32:02 +00:00
|
|
|
# **wexpect**
|
2019-04-24 08:10:16 +00:00
|
|
|
|
2019-09-05 14:20:37 +00:00
|
|
|
[![Build status](https://ci.appveyor.com/api/projects/status/tbji72d5s0tagrt9?svg=true)](https://ci.appveyor.com/project/raczben/wexpect)
|
2019-09-06 09:52:11 +00:00
|
|
|
[![codecov](https://codecov.io/gh/raczben/wexpect/branch/master/graph/badge.svg)](https://codecov.io/gh/raczben/wexpect)
|
2019-09-05 14:20:37 +00:00
|
|
|
|
2019-04-24 14:32:02 +00:00
|
|
|
*Wexpect* is a Windows variant of [pexpect](https://pexpect.readthedocs.io/en/stable/).
|
2019-04-24 08:10:16 +00:00
|
|
|
|
2019-04-24 14:32:02 +00:00
|
|
|
*Pexpect* is a Python module for spawning child applications and controlling
|
|
|
|
them automatically.
|
2019-04-24 08:10:16 +00:00
|
|
|
|
2019-09-05 14:20:37 +00:00
|
|
|
## You need wexpect if...
|
2019-05-05 15:54:10 +00:00
|
|
|
|
2019-09-06 09:52:11 +00:00
|
|
|
- you want to control any windows console application from python script.
|
|
|
|
- you want to write test-automation script for a windows console application.
|
|
|
|
- you want to automate your job by controlling multiple application parallel, synchoronusly.
|
2019-05-05 15:54:10 +00:00
|
|
|
|
2019-04-24 14:32:02 +00:00
|
|
|
## **Install**
|
2019-04-24 08:10:16 +00:00
|
|
|
|
2019-04-24 14:32:02 +00:00
|
|
|
pip install wexpect
|
2019-09-05 14:20:37 +00:00
|
|
|
|
|
|
|
OR
|
|
|
|
|
|
|
|
Because wexpect a tiny project dropping the wexpect.py file into your working directory is usually
|
|
|
|
good enough instead of installing. However in this case you need to install manually the pypiwin32
|
|
|
|
dependence.
|
|
|
|
|
|
|
|
|
2019-04-24 14:32:02 +00:00
|
|
|
## **Usage**
|
2019-04-24 08:10:16 +00:00
|
|
|
|
2019-04-24 14:32:02 +00:00
|
|
|
To interract with a child process use `spawn` method:
|
2019-04-24 08:10:16 +00:00
|
|
|
|
2019-05-05 15:54:10 +00:00
|
|
|
```python
|
|
|
|
import wexpect
|
|
|
|
child = wexpect.spawn('cmd.exe')
|
|
|
|
child.expect('>')
|
|
|
|
child.sendline('ls')
|
|
|
|
child.expect('>')
|
|
|
|
print(child.before)
|
2019-09-05 15:51:27 +00:00
|
|
|
child.sendline('exit')
|
2019-05-05 15:54:10 +00:00
|
|
|
```
|
2019-04-24 08:10:16 +00:00
|
|
|
|
2019-04-24 14:32:02 +00:00
|
|
|
For more information see [examples](./examples) folder.
|
2019-04-24 08:10:16 +00:00
|
|
|
|
2020-01-31 14:49:48 +00:00
|
|
|
---
|
|
|
|
## **REFACTOR**
|
|
|
|
|
|
|
|
The original wexpect has some structural weakness, which leads me to rewrite the whole code. The
|
|
|
|
first variant of the new structure is delivered with [v3.2.0](https://pypi.org/project/wexpect/3.2.0/).
|
|
|
|
Note, that the default is the old variant (`legacy_wexpect`), to use the new you need to set the
|
|
|
|
`WEXPECT_SPAWN_CLASS` environment variable to `SpawnPipe` or `SpawnSocket`, which are the two new
|
|
|
|
structured spawn class.
|
|
|
|
|
|
|
|
### Old vs new
|
|
|
|
|
|
|
|
But what is the difference between the old and new and what was the problem with the old?
|
|
|
|
|
|
|
|
Generally, wexpect (both old and new) has three processes:
|
|
|
|
|
|
|
|
- *host* is our original pyton script/program, which want to launch the child.
|
|
|
|
- *console* is a process which started by the host, and launches the child. (This is a python script)
|
|
|
|
- *child* is the process which want to be launced.
|
|
|
|
|
|
|
|
The child and the console has a common Windows console, distict from the host.
|
|
|
|
|
|
|
|
The `legacy_wexpect`'s console is a thin script, almost do nothing. It initializes the Windows's
|
|
|
|
console, and monitors the host and child processes. The magic is done by the host process, which has
|
|
|
|
the switchTo() and switchBack() functions, which (de-) attaches the *child-console* Windows-console.
|
|
|
|
The host manipulates the child's console directly. This direct manipuation is the structural weakness.
|
|
|
|
The following task/usecases are hard/impossibile:
|
|
|
|
|
|
|
|
- thread-safe multiprocessing of the host.
|
|
|
|
- logging (both console and host)
|
|
|
|
- using in grapichal IDE or with pytest
|
|
|
|
- This variant is highly depends on the pywin32 package.
|
|
|
|
|
|
|
|
The new structure's console is a thik script. The console process do the major console manipulation,
|
|
|
|
which is controlled by the host via socket (see SpawnSocket) or named-pipe (SpawnPipe). The host
|
|
|
|
only process the except-loops.
|
|
|
|
|
2019-04-24 14:32:02 +00:00
|
|
|
---
|
|
|
|
## What is it?
|
2019-04-24 08:10:16 +00:00
|
|
|
|
2019-04-24 14:32:02 +00:00
|
|
|
Wexpect is a Python module for spawning child applications and controlling
|
|
|
|
them automatically. Wexpect can be used for automating interactive applications
|
|
|
|
such as ssh, ftp, passwd, telnet, etc. It can be used to a automate setup
|
|
|
|
scripts for duplicating software package installations on different servers. It
|
|
|
|
can be used for automated software testing. Wexpect is in the spirit of Don
|
|
|
|
Libes' Expect, but Wexpect is pure Python. Other Expect-like modules for Python
|
|
|
|
require TCL and Expect or require C extensions to be compiled. Wexpect does not
|
|
|
|
use C, Expect, or TCL extensions.
|
2019-04-24 08:10:16 +00:00
|
|
|
|
2019-04-24 14:32:02 +00:00
|
|
|
Original Pexpect should work on any platform that supports the standard Python pty module. While
|
|
|
|
Wexpect works on Windows platforms. The Wexpect interface focuses on ease of use so that simple
|
|
|
|
tasks are easy.
|
2019-04-24 08:10:16 +00:00
|
|
|
|
|
|
|
|
2019-04-24 14:32:02 +00:00
|
|
|
### History
|
2019-04-24 10:09:19 +00:00
|
|
|
|
2019-04-24 14:32:02 +00:00
|
|
|
Wexpect is a one-file code developed at University of Washington. There are several
|
|
|
|
[copy](https://gist.github.com/anthonyeden/8488763) and
|
|
|
|
[reference](https://mediarealm.com.au/articles/python-pexpect-windows-wexpect/)
|
|
|
|
to this code with very few (almost none) documentation nor integration.
|
|
|
|
|
|
|
|
This repo tries to fix these limitations, with a few example code and pypi integration.
|
2019-04-24 10:09:19 +00:00
|
|
|
|
2019-04-24 08:10:16 +00:00
|
|
|
|
2019-05-05 15:54:10 +00:00
|
|
|
---
|
|
|
|
## Dev
|
|
|
|
|
|
|
|
Thanks for any contributing!
|
|
|
|
|
2019-07-29 12:21:26 +00:00
|
|
|
### Test
|
|
|
|
|
2019-05-05 15:54:10 +00:00
|
|
|
To run test, enter into the folder of the wexpect's repo then:
|
|
|
|
|
2019-07-29 12:21:26 +00:00
|
|
|
`python -m unittest`
|
|
|
|
|
2019-09-23 13:58:02 +00:00
|
|
|
### Deploy
|
|
|
|
|
|
|
|
The deployment itself is automated and done by [appveyor](https://ci.appveyor.com/project/raczben/wexpect).
|
|
|
|
See `after_test` section in [appveyor.yml](appveyor.yml) for more details.
|
2019-07-29 12:21:26 +00:00
|
|
|
|
|
|
|
The wexpect uses [pbr](https://docs.openstack.org/pbr/latest/) for managing releasing procedures.
|
2019-09-23 13:58:02 +00:00
|
|
|
The versioning is handled by the pbr. The *"master-version"* is the git tag. Pbr derives the package
|
|
|
|
version from the git tags.
|
2019-07-29 12:21:26 +00:00
|
|
|
|
2019-09-19 13:26:01 +00:00
|
|
|
## Basic behaviour
|
2019-07-29 12:21:26 +00:00
|
|
|
|
2019-09-19 13:26:01 +00:00
|
|
|
Let's go through the example code:
|
2019-07-29 12:21:26 +00:00
|
|
|
|
2019-09-19 13:26:01 +00:00
|
|
|
```python
|
|
|
|
import wexpect
|
|
|
|
child = wexpect.spawn('cmd.exe')
|
|
|
|
child.expect('>')
|
|
|
|
child.sendline('ls')
|
|
|
|
child.expect('>')
|
|
|
|
print(child.before)
|
|
|
|
child.sendline('exit')
|
|
|
|
```
|
|
|
|
|
|
|
|
### spawn()
|
|
|
|
|
|
|
|
`child = wexpect.spawn('cmd.exe')`
|
|
|
|
|
|
|
|
Call trace:
|
|
|
|
|
2019-12-22 09:51:46 +00:00
|
|
|
- ::spawn
|
|
|
|
- spawn_windows::__init__()
|
|
|
|
- spawn_windows::_spawn()
|
|
|
|
- Wtty::spawn()
|
|
|
|
- Wtty::startChild()
|
|
|
|
- win32process.CreateProcess()
|
2019-09-19 13:26:01 +00:00
|
|
|
|
|
|
|
|
|
|
|
### expect()
|
|
|
|
|
|
|
|
`child.expect('>')`
|
|
|
|
|
|
|
|
Call trace:
|
|
|
|
|
2019-12-22 09:51:46 +00:00
|
|
|
- spawn_windows::expect()
|
|
|
|
- spawn_windows::expect_list()
|
|
|
|
- spawn_windows::expect_loop()
|
|
|
|
- spawn_windows::read_nonblocking()
|
2019-09-19 13:26:01 +00:00
|
|
|
- Wtty::read_nonblocking()
|
|
|
|
- Wtty::readConsoleToCursor()
|
2019-12-22 09:51:46 +00:00
|
|
|
- Wtty::readConsole()
|
|
|
|
- __consout.ReadConsoleOutputCharacter()
|
2019-09-19 13:26:01 +00:00
|
|
|
|
2019-05-05 15:54:10 +00:00
|
|
|
|
2019-09-20 08:51:58 +00:00
|
|
|
### sendline()
|
|
|
|
|
|
|
|
`child.sendline('ls')`
|
|
|
|
|
2019-12-22 09:51:46 +00:00
|
|
|
- spawn_windows::sendline()
|
|
|
|
- spawn_windows::send()
|
|
|
|
- Wtty::write()
|