I am trying to create a tool from a python script I have written that will take a list I have created and use it as a drop-down menu in the finished tool as one of the inputs (see attached image for example):
The list I am using is a large list that includes all the towns in the state of Vermont, and I generate it in the script from a table (see code below). I suspect my problem at the moment is just with setting the tool Properties to take this list and use it to create a drop-down list for the user. Here is the block of code that creates the list for use in the parameter - does anybody see any problems with this code-end of the tool?
import arcpy arcpy.env.workspace = "Z:OPSTechnicalServicesCulvertsGetCulvertsGetCulverts.gdb" towns = "Database ConnectionsGDB_GEN.sdeGDB_Gen.VTRANS_ADMIN.townindex" arcpy.MakeFeatureLayer_management(towns,"towns_lyr") NameList =  NameListArray = set() rows = arcpy.SearchCursor("towns_lyr") for row in rows: value = row.getValue("TOWNNAME") if value not in NameListArray: NameList.append(value) town = NameList town = arcpy.GetParameterAsText(0)
Here is an image of the Tool properties as well, with the default validation code - do I need to alter this validation code?
I looked for info on altering this validation code, but I could not find info on using it for formatting drop-down lists.
Try setting the tool validator class code to this:
import arcpy class ToolValidator(object): """Class for validating a tool's parameter values and controlling the behavior of the tool's dialog.""" def __init__(self): """Setup arcpy and the list of tool parameters.""" self.params = arcpy.GetParameterInfo() def initializeParameters(self): """Refine the properties of a tool's parameters. This method is called when the tool is opened.""" return def updateParameters(self): """Modify the values and properties of parameters before internal validation is performed. This method is called whenever a parameter has been changed.""" towns = "Database ConnectionsGDB_GEN.sdeGDB_Gen.VTRANS_ADMIN.townindex" rows = arcpy.SearchCursor(towns) self.params.filter.list = sorted(list(set(r.getValue('TOWNNAME') for r in rows))) del rows return def updateMessages(self): """Modify the messages created by internal validation for each tool parameter. This method is called after internal validation.""" return
I have a JQuery UI with a bunch of sliders. Each slider code looks like this:
There needs to be some accompanying JQuery that does something like this:
Obviously two major things have to change about the JS. First, it needs to execute when the slider is released (not on page load), and second it needs to actually pass the value of the slider to the Python script some how. I set it up like this just to test. When I load the page, this tester python script is executed correctly, and some hardware connected to the Raspberry Pi is controlled properly. I know I should be using the slidestop event, but I can't get it to work. I'm also not sure of what is the BEST way to send some variables to the python script.
My python script looks like this, right now: #!/usr/bin/python
I'm looking forward to any insight that folks might have on either high level issues, or ways to solve more specific problems that I've listed here.
Create permanent run/debug configurations
PyCharm provides the following ways to create a permanent run/debug configuration:
Create from a template or copy an existing configuration.
Save a temporary configuration as permanent
Select a temporary configuration in the run/debug configuration switcher and then click Save Configuration .
Once you save a temporary configuration, it becomes permanent and it is recorded in a separate XML file in the <project directory>/.idea/ directory. For example, MyProject/.idea/Car.xml .
Alternatively, select a temporary configuration in the Run/debug configurations dialog and click on the toolbar.
PyCharm provides run/debug configuration templates for different languages, tools, and frameworks. The list of available templates varies depending on the installed/bundled plugins.
Create a run/debug configuration from a template
Open the Run/Debug Configuration dialog in one of the following ways:
Select Run | Edit Configurations from the main menu.
With the Navigation bar visible ( View | Appearance | Navigation Bar ), choose Edit Configurations from the run/debug configuration selector.
Press Alt+Shift+F10 , then press 0 or select the configuration from the popup and press F4 .
In the Run/Debug Configuration dialog, click on the toolbar or press Alt+Insert . The list shows the run/debug configuration templates.
Select the desired template. If you are not sure which template to choose, refer to Run/debug configurations dialog for more information on particular templates.
Specify the run/debug configuration name in the Name field. This name will be shown in the list of the available run/debug configurations.
Select Allow parallel run if you want to allow multiple instances of the configuration to run at the same time. If this option is disabled, attempting to re-run the configuration will terminate the active session.
In the Before launch section, define whether you want to perform any specific actions before launching the application, for example, execute some tools or scripts prior to launching the run/debug configuration.
For information on particular Before launch activities, refer to Before Launch
Apply the changes and close the dialog.
Setting up Drop-Down list in Parameters of Python script tool? - Geographic Information Systems
To find out what the different settings are for, just leave your mouse pointer a second on the editbox/checkbox. and a helpful tooltip will popup.
Figure 4.72. The Settings Dialog, General Page
This dialog allows you to specify your preferred language, and the Subversion-specific settings.
Selects your user interface language. Of course, you have to install the corresponding language pack first to get another UI language than the default English one.
TortoiseSVN will contact its download site periodically to see if there is a newer version of the program available. If there is it will show a notification link in the commit dialog. Use Check now if you want an answer right away. The new version will not be downloaded you simply receive an information dialog telling you that the new version is available.
TortoiseSVN has three custom sounds which are installed by default.
You can select different sounds (or turn these sounds off completely) using the Windows Control Panel. Configure is a shortcut to the Control Panel.
On Windows Vista and later systems this controls whether dialogs use the Aero styling.
On Windows 7 you can create a Library in which to group working copies which are scattered in various places on your system.
Global ignore patterns are used to prevent unversioned files from showing up e.g. in the commit dialog. Files matching the patterns are also ignored by an import. Ignore files or directories by typing in the names or extensions. Patterns are separated by spaces e.g. bin obj *.bak *.
?? *.jar *.[Tt]mp . These patterns should not include any path separators. Note also that there is no way to differentiate between files and directories. Read the section called “Pattern Matching in Ignore Lists” for more information on the pattern-matching syntax.
Note that the ignore patterns you specify here will also affect other Subversion clients running on your PC, including the command line client.
If you use the Subversion configuration file to set a global-ignores pattern, it will override the settings you make here. The Subversion configuration file is accessed using the Edit as described below.
This ignore pattern will affect all your projects. It is not versioned, so it will not affect other users. By contrast you can also use the versioned svn:ignore or svn:global-ignores property to exclude files or directories from version control. Read the section called “Ignoring Files And Directories” for more information.
Set file dates to the “ last commit time ”
This option tells TortoiseSVN to set the file dates to the last commit time when doing a checkout or an update. Otherwise TortoiseSVN will use the current date. If you are developing software it is generally best to use the current date because build systems normally look at the date stamps to decide which files need compiling. If you use “ last commit time ” and revert to an older file revision, your project may not compile as you expect it to.
Subversion configuration file
Use Edit to edit the Subversion configuration file directly. Some settings cannot be modified directly by TortoiseSVN, and need to be set here instead. For more information about the Subversion config file see the Runtime Configuration Area . The section on Automatic Property Setting is of particular interest, and that is configured here. Note that Subversion can read configuration information from several places, and you need to know which one takes priority. Refer to Configuration and the Windows Registry to find out more.
Apply local modifications to svn:externals when updating
This option tells TortoiseSVN to always apply local modifications to the svn:externals property when updating the working copy.
Context Menu Settings
Figure 4.73. The Settings Dialog, Context Menu Page
This page allows you to specify which of the TortoiseSVN context menu entries will show up in the main context menu, and which will appear in the TortoiseSVN submenu. By default most items are unchecked and appear in the submenu.
There is a special case for Get Lock . You can of course promote it to the top level using the list above, but as most files don't need locking this just adds clutter. However, a file with the svn:needs-lock property needs this action every time it is edited, so in that case it is very useful to have at the top level. Checking the box here means that when a file is selected which has the svn:needs-lock property set, Get Lock will always appear at the top level.
Most of the time, you won't need the TortoiseSVN context menu, apart for folders that are under version control by Subversion. For non- versioned folders, you only really need the context menu when you want to do a checkout. If you check the option Hide menus for unversioned paths , TortoiseSVN will not add its entries to the context menu for unversioned folders. But the entries are added for all items and paths in a versioned folder. And you can get the entries back for unversioned folders by holding the Shift key down while showing the context menu.
If there are some paths on your computer where you just don't want TortoiseSVN's context menu to appear at all, you can list them in the box at the bottom.
TortoiseSVN Dialog Settings 1
Figure 4.74. The Settings Dialog, Dialogs 1 Page
This dialog allows you to configure some of TortoiseSVN's dialogs the way you like them.
Limits the number of log messages that TortoiseSVN fetches when you first select TortoiseSVN → Show Log Useful for slow server connections. You can always use Show All or Next 100 to get more messages.
Selects the font face and size used to display the log message itself in the middle pane of the Revision Log dialog, and when composing log messages in the Commit dialog.
Short date / time format in log messages
If the standard long messages use up too much space on your screen use the short format.
Can double click in log list to compare with previous revision
If you frequently find yourself comparing revisions in the top pane of the log dialog, you can use this option to allow that action on double click. It is not enabled by default because fetching the diff is often a long process, and many people prefer to avoid the wait after an accidental double click, which is why this option is not enabled by default.
TortoiseSVN can automatically close all progress dialogs when the action is finished without error. This setting allows you to select the conditions for closing the dialogs. The default (recommended) setting is Close manually which allows you to review all messages and check what has happened. However, you may decide that you want to ignore some types of message and have the dialog close automatically if there are no critical changes.
Auto-close if no merges, adds or deletes means that the progress dialog will close if there were simple updates, but if changes from the repository were merged with yours, or if any files were added or deleted, the dialog will remain open. It will also stay open if there were any conflicts or errors during the operation.
Auto-close if no conflicts relaxes the criteria further and will close the dialog even if there were merges, adds or deletes. However, if there were any conflicts or errors, the dialog remains open.
Auto-close if no errors always closes the dialog even if there were conflicts. The only condition that keeps the dialog open is an error condition, which occurs when Subversion is unable to complete the task. For example, an update fails because the server is inaccessible, or a commit fails because the working copy is out-of-date.
Always close dialogs for local operations
Local operations like adding files or reverting changes do not need to contact the repository and complete quickly, so the progress dialog is often of little interest. Select this option if you want the progress dialog to close automatically after these operations, unless there are errors.
Use recycle bin when reverting
When you revert local modifications, your changes are discarded. TortoiseSVN gives you an extra safety net by sending the modified file to the recycle bin before bringing back the pristine copy. If you prefer to skip the recycle bin, uncheck this option.
Use URL of WC as the default “ From: ” URL
In the merge dialog, the default behaviour is for the From: URL to be remembered between merges. However, some people like to perform merges from many different points in their hierarchy, and find it easier to start out with the URL of the current working copy. This can then be edited to refer to a parallel path on another branch.
You can specify the default path for checkouts. If you keep all your checkouts in one place, it is useful to have the drive and folder pre-filled so you only have to add the new folder name to the end.
You can also specify the default URL for checkouts. If you often checkout sub-projects of some very large project, it can be useful to have the URL pre-filled so you only have to add the sub-project name to the end.
You can do this using the splat operator:
This causes the function to receive each list item as a separate parameter. There's a description here: http://docs.python.org/tutorial/controlflow.html#unpacking-argument-lists
This has already been answered perfectly, but since I just came to this page and did not understand immediately I am just going to add a simple but complete example.
With Click, you can build CLI easily compared to Argparse. Click solves the same problem argparse solves, but uses a slightly different approach to do so. It uses the concept of decorators. This needs commands to be functions that can be wrapped using decorators.
You can add argument and option like below:
If you run the above scripts, you should get:
Putting everything together, I was able to build a simple CLI to query books on Google Books.
For more info, you can dig deep on Click from the official documentation
Editing and navigation¶
IDLE may open editor windows when it starts, depending on settings and how you start IDLE. Thereafter, use the File menu. There can be only one open editor window for a given file.
The title bar contains the name of the file, the full path, and the version of Python and IDLE running the window. The status bar contains the line number (‘Ln’) and column number (‘Col’). Line numbers start with 1 column numbers with 0.
IDLE assumes that files with a known .py* extension contain Python code and that other files do not. Run Python code with the Run menu.
In this section, ‘C’ refers to the Control key on Windows and Unix and the Command key on macOS.
Backspace deletes to the left Del deletes to the right
C-Backspace delete word left C-Del delete word to the right
Arrow keys and Page Up / Page Down to move around
C-LeftArrow and C-RightArrow moves by words
Home / End go to begin/end of line
C-Home / C-End go to begin/end of file
Some useful Emacs bindings are inherited from Tcl/Tk:
C-a beginning of line
C-e end of line
C-k kill line (but doesn’t put it in clipboard)
C-l center window around the insertion point
C-b go backward one character without deleting (usually you can also use the cursor key for this)
C-f go forward one character without deleting (usually you can also use the cursor key for this)
C-p go up one line (usually you can also use the cursor key for this)
C-d delete next character
Standard keybindings (like C-c to copy and C-v to paste) may work. Keybindings are selected in the Configure IDLE dialog.
After a block-opening statement, the next line is indented by 4 spaces (in the Python Shell window by one tab). After certain keywords (break, return etc.) the next line is dedented. In leading indentation, Backspace deletes up to 4 spaces if they are there. Tab inserts spaces (in the Python Shell window one tab), number depends on Indent width. Currently, tabs are restricted to four spaces due to Tcl/Tk limitations.
See also the indent/dedent region commands on the Format menu .
Completions are supplied, when requested and available, for module names, attributes of classes or functions, or filenames. Each request method displays a completion box with existing names. (See tab completions below for an exception.) For any box, change the name being completed and the item highlighted in the box by typing and deleting characters by hitting Up , Down , PageUp , PageDown , Home , and End keys and by a single click within the box. Close the box with Escape , Enter , and double Tab keys or clicks outside the box. A double click within the box selects and closes.
One way to open a box is to type a key character and wait for a predefined interval. This defaults to 2 seconds customize it in the settings dialog. (To prevent auto popups, set the delay to a large number of milliseconds, such as 100000000.) For imported module names or class or function attributes, type ‘.’. For filenames in the root directory, type os.sep or os.altsep immediately after an opening quote. (On Windows, one can specify a drive first.) Move into subdirectories by typing a directory name and a separator.
Instead of waiting, or after a box is closed, open a completion box immediately with Show Completions on the Edit menu. The default hot key is C-space . If one types a prefix for the desired name before opening the box, the first match or near miss is made visible. The result is the same as if one enters a prefix after the box is displayed. Show Completions after a quote completes filenames in the current directory instead of a root directory.
Hitting Tab after a prefix usually has the same effect as Show Completions. (With no prefix, it indents.) However, if there is only one match to the prefix, that match is immediately added to the editor text without opening a box.
Invoking ‘Show Completions’, or hitting Tab after a prefix, outside of a string and without a preceding ‘.’ opens a box with keywords, builtin names, and available module-level names.
When editing code in an editor (as oppose to Shell), increase the available module-level names by running your code and not restarting the Shell thereafter. This is especially useful after adding imports at the top of a file. This also increases possible attribute completions.
Completion boxes intially exclude names beginning with ‘_’ or, for modules, not included in ‘__all__’. The hidden names can be accessed by typing ‘_’ after ‘.’, either before or after the box is opened.
A calltip is shown automatically when one types ( after the name of an accessible function. A function name expression may include dots and subscripts. A calltip remains until it is clicked, the cursor is moved out of the argument area, or ) is typed. Whenever the cursor is in the argument part of a definition, select Edit and “Show Call Tip” on the menu or enter its shortcut to display a calltip.
The calltip consists of the function’s signature and docstring up to the latter’s first blank line or the fifth non-blank line. (Some builtin functions lack an accessible signature.) A ‘/’ or ‘*’ in the signature indicates that the preceding or following arguments are passed by position or name (keyword) only. Details are subject to change.
In Shell, the accessible functions depends on what modules have been imported into the user process, including those imported by Idle itself, and which definitions have been run, all since the last restart.
For example, restart the Shell and enter itertools.count( . A calltip appears because Idle imports itertools into the user process for its own use. (This could change.) Enter turtle.write( and nothing appears. Idle does not itself import turtle. The menu entry and shortcut also do nothing. Enter import turtle . Thereafter, turtle.write( will display a calltip.
In an editor, import statements have no effect until one runs the file. One might want to run a file after writing import statements, after adding function definitions, or after opening an existing file.
Within an editor window containing Python code, code context can be toggled in order to show or hide a pane at the top of the window. When shown, this pane freezes the opening lines for block code, such as those beginning with class , def , or if keywords, that would have otherwise scrolled out of view. The size of the pane will be expanded and contracted as needed to show the all current levels of context, up to the maximum number of lines defined in the Configure IDLE dialog (which defaults to 15). If there are no current context lines and the feature is toggled on, a single blank line will display. Clicking on a line in the context pane will move that line to the top of the editor.
The text and background colors for the context pane can be configured under the Highlights tab in the Configure IDLE dialog.
Python Shell window¶
With IDLE’s Shell, one enters, edits, and recalls complete statements. Most consoles and terminals only work with a single physical line at a time.
When one pastes code into Shell, it is not compiled and possibly executed until one hits Return . One may edit pasted code first. If one pastes more that one statement into Shell, the result will be a SyntaxError when multiple statements are compiled as if they were one.
The editing features described in previous subsections work when entering code interactively. IDLE’s Shell window also responds to the following keys.
C-c interrupts executing command
C-d sends end-of-file closes window if typed at a >>> prompt
Alt-/ (Expand word) is also useful to reduce typing
Alt-p retrieves previous command matching what you have typed. On macOS use C-p .
Alt-n retrieves next. On macOS use C-n .
Return while on any previous command retrieves that command
Idle defaults to black on white text, but colors text with special meanings. For the shell, these are shell output, shell error, user output, and user error. For Python code, at the shell prompt or in an editor, these are keywords, builtin class and function names, names following class and def , strings, and comments. For any text window, these are the cursor (when present), found text (when possible), and selected text.
Text coloring is done in the background, so uncolorized text is occasionally visible. To change the color scheme, use the Configure IDLE dialog Highlighting tab. The marking of debugger breakpoint lines in the editor and text in popups and dialogs is not user-configurable.
Making a quick GUI
When is PySimpleGUI useful? Immediately, whenever you need a GUI. It takes less than five minutes to create and try a GUI. The quickest way to make a GUI is to copy one from the PySimpleGUI Cookbook. Follow these steps:
- Find a GUI that looks similar to what you want to create
- Copy code from the Cookbook
- Paste it into your IDE and run it
Let's look at the first recipe from the book.
It's a reasonably sized form.
Go Beyond ArcGIS’s Standard Slope Tool with Python Customization
Digital elevation models are an important part of many geographic information system datasets and studies. Further, the distribution and characterization of topographic attributes across a landscape can be vital information for geomorphological, hydrological, and biological applications (Moore et al. 1991). Equally important are the parameters calculated from DEMs. Slope is, perhaps, the most common. However, the standard slope tool in ArcGIS (10.4.1) only examines a 3x3 neighborhood and does not include the center cell. [For a more complete discussion of slope calculations, see Hickey et al (1994) and Dunn and Hickey (1998).] While this is acceptable for a broader-scale examination of slope, customization of ArcGIS terrain processing tools with Python code can help us calculate slope along directions specific to a researcher’s needs. Theoretical applications of a directional slope tool might include finding the slope along a stream’s natural path, anticipating the direction of water flowing across a surface, investigating the direction of wildfire’s movement across diverse terrain, or measuring the relative slope direction along a hiking trail.
This article addresses a method for calculating slope along a flow direction grid. In the hydrologic example, this would be the equivalent of calculating the maximum downhill slope angle. If the user is interested in the slope along any other direction — for example, along the direction of a moving fire, stream, or trail — an FD grid must be created which represents the direction of movement along the feature under investigation.
The objective of this project is to calculate slope angle based upon a combination of a DEM and the output of an FD calculation. The input to FD is typically a DEM, and the output identifies one of eight surrounding cells with the direction of the steepest slope inclination. The output is coded as shown in Figure 1.
Figure 1: FLOWDIRECTION output
Alternatively, FD can be calculated from any other raster layer. For example, a user could create a raster dataset which depicts fire movement, and then FD can be calculated from this data plus a DEM.
Regardless of the intended application, the code presented here takes DEM and flow direction output rasters and calculates directional slope by calculating slope (rise/run) from the center kernel cell to the single adjacent cell along the subsequent FD raster.
For the curious, the workflow is shown below in legacy AML code (Hickey et al, 1994). FLOW is the FD grid (see Figure 1), DEM is the filled DEM, SIZE is the pixel size, DIAG is 1.4*pixel size (or the diagonal distance between two adjacent pixels), and ANGLE is the calculated slope:
To implement this approach using Python, we converted the raster to a NumPy array. NumPy is a special Python module for working with math and numbers. A NumPy array can store values that represent rows and columns in a grid. A programmer can then get the value of any cell in the raster by referencing the cell’s row and column. This allows for making customized calculations using values from adjacent grid cells, something that is not only useful for customizing slope, but any kind of neighborhood statistic.
Convert the DEM and flow direction rasters to NumPy arrays like this:
Later in the code, we set up some Python tuples of flow directions, using the term rook for adjacent cells and diag for diagonal cells.
Then later on, after finding the difference in elevation between the pixels along the FD, we can apply the correct slope calculation depending on the flow direction. Note that the Python code below shows slope as a percentage, whereas the AML above used degrees. You can apply whichever approach you want by modifying the math:
For this to work properly, all inputs must be in a file geodatabase. Also remember that, for any raster neighborhood operation, the outer rows/columns are always inaccurate and the user should work off a study area that is larger than necessary – and only clip to the final area after all analyses are complete.
A link to the full code is provided at the end of this article.
Sample Project Walkthrough
The study site is near a popular hiking trail outside Ellensburg, Wash. (Figure 2). It was chosen due to the relatively straightforward topography, lack of vegetation cover, (shrub steppe ecosystem), and familiarity to the authors. Our goals were to first calculate the maximum downhill slope angle (slope along the direction of water flow) and then, to calculate slope along the direction a simulated fire might propagate. A 10-meter DEM covering the study area extent was downloaded from the USGS online data library, Earth Explorer, stored in a .dem format, and imported into an ArcGIS file geodatabase. All data was spatially referenced using NAD27 - UTM zone 10N. All data was clipped to an area a bit larger than the area of interest. We then ran the Fill tool on the DEM to remove sinks and small data issues. [Author’s note: Always run Fill it cleans up minor issues that seem to be prevalent in any DEM you might download.]
Figure 2. Oblique view of the study area, looking south. The burn area is highlighted in red the fire started to the far right (west).
Following the study area data clip and the DEM fill operation, FlowDirection was used to create an FD raster. Finally, the presented directional slope script was run on the data. The output is the maximum downhill slope angle (Figure 3).
Figure 3. Upper left, DEM of study area with fire aoi for reference. Upper right, hillshade. Lower left, flowdirection output. Lower right, maximum downhill slope angle.
To examine the slope along which a simulated fire would travel, we digitized a series of fire lines, assuming these represented the location of the fire line at different times. We also created a polygon file representing the total area burned. It’s important that these vector files be in the same datum/coordinate system as the DEM.
We then assigned “elevations” to the fire. The numbers themselves don’t really matter as long as the highest values are where the fire started and the lowest, where it finished. We then ran the Topo to Raster tool on the fire lines. When doing this, make sure to use the clipped DEM as the input to the “output cell size” and “output extent” (Figure 4). This will ensure that the DEM and your new fire raster overlay exactly. Run Fill on this fire raster, then FlowDirection. This FD layer will represent the direction the ‘fire’ is moving (Figure 5).
Figure 4: DEM created from the fire lines. Fire lines (with labels, 100 was where the fire started it finished at 30) and fire AOI for reference. This is the same AOI as is shown in Figure 3.
Figure 5: FLOWDIRECTION output based on the fire dem in Figure 4.
We then ran our script using the DEM and the fire FD layers as inputs. The output is the slope of the land according to the direction of the moving fire (Figure 6).
Figure 6: Slope angle along the direction of fire movement. Note, negative values represent areas where the fire is moving uphill green is downhill.
Are you getting odd results? Very high or low values? Or even large areas with a 0 slope? Here are some suggestions for things to check:
- Is everything in the same datum/coordinate system? Never use geographic (lat/long) coordinates when working with raster data.
- Did you remember to run Fill on your DEM?
- Ensure that all the raster layers overlay perfectly and have the same number of rows, columns, and cell size.
- Ensure that the vertical units are the same as the horizontal units (meters or feet).
- All your input files should be within a file geodatabase.
If you need to go beyond the out-of-the-box functionality of the ArcGIS raster analysis tools, you can use the ArcPy site package to write custom tools. A particularly powerful way to work with DEMs is to use NumPy arrays to iterate through each cell and apply your own formulas. We’ve demonstrated this by implementing a calculation to find directional slope. The walkthrough project describes how such a tool can be applied toward either modeling the path of a wildfire or of water flowing downhill. The code is available at http://www.onlinegeographer.com/slope/slope.html.
Dunn, M. and R. Hickey, 1998, The Effect of Slope Algorithms on Slope Estimates within a GIS. Cartography. V. 27, no. 1, pp. 9–15.
Hickey, R, A. Smith, and P. Jankowski, 1994, Slope length Calculations from a DEM with in ARC/INFO GRID. Computers, Environment and Urban Systems, v. 18, no. 5, pp. 365 - 380.
Moore, I. D., Grayson, R. B., & Ladson, A. R. (1991). Digital terrain modelling: a review of hydrological, geomorphological, and biological applications. Hydrological processes, 5(1), 3-30.
Geolocation is a simple and clever application which uses google maps api.
- Geocode Module allows you to easily and quickly get information about given location.
- country short form,
- street number,
- postal code,
- formatted address,
- administrative areas,
- Distance Module allows you to get information about travel distance and time for a matrix of origins and destinations.
- origin address,
- destination address,
- distance: kilometers, meters, miles.
20 CONTROLLING THE KEYBOARD AND MOUSE WITH GUI AUTOMATION
Knowing various Python modules for editing spreadsheets, downloading files, and launching programs is useful, but sometimes there just aren’t any modules for the applications you need to work with. The ultimate tools for automating tasks on your computer are pro­grams you write that directly control the keyboard and mouse. These programs can control other applications by sending them virtual keystrokes and mouse clicks, just as if you were sitting at your computer and interacting with the applications yourself.
This technique is known as graphical user interface automation, or GUI automation for short. With GUI automation, your programs can do anything that a human user sitting at the computer can do, except spill coffee on the keyboard. Think of GUI automation as programming a robotic arm. You can program the robotic arm to type at your keyboard and move your mouse for you. This technique is particularly useful for tasks that involve a lot of mindless clicking or filling out of forms.
Some companies sell innovative (and pricey) “automation solutions,” usually marketed as robotic process automation (RPA). These products are effectively no different than the Python scripts you can make yourself with the pyautogui module, which has functions for simulating mouse movements, button clicks, and mouse wheel scrolls. This chapter covers only a subset of PyAutoGUI’s features you can find the full documentation at https://pyautogui.readthedocs.io/.
Installing the pyautogui Module
The pyautogui module can send virtual keypresses and mouse clicks to Windows, macOS, and Linux. Windows and macOS users can simply use pip to install PyAutoGUI. However, Linux users will first have to install some software that PyAutoGUI depends on. Open a terminal window and enter the following commands:
- sudo apt-get install scrot
- sudo apt-get install python3-tk
- sudo apt-get install python3-dev
To install PyAutoGUI, run pip install --user pyautogui . Don’t use sudo with pip you may install modules to the Python installation that the operating system uses, causing conflicts with any scripts that rely on its original configuration. However, you should use the sudo command when installing applications with apt-get .
Appendix A has complete information on installing third-party modules. To test whether PyAutoGUI has been installed correctly, run import pyautogui from the interactive shell and check for any error messages.
Don’t save your program as pyautogui.py. When you run import pyautogui , Python will import your program instead of the PyAutoGUI and you’ll get error messages like AttributeError: module 'pyautogui' has no attribute 'click' .
Setting Up Accessibility Apps on macOS
As a security measure, macOS doesn’t normally let programs control the mouse or keyboard. To make PyAutoGUI work on macOS, you must set the program running your Python script to be an accessibility application. Without this step, your PyAutoGUI function calls will have no effect.
Whether you run your Python programs from Mu, IDLE, or the Terminal, have that application open. Then open the System Preferences and go to the Accessibility tab. The currently open applications will appear under the “Allow the apps below to control your computer” label. Check Mu, IDLE, Terminal, or whichever app you use to run your Python scripts. You’ll be prompted to enter your password to confirm these changes.
Staying on Track
Before you jump into a GUI automation, you should know how to escape problems that may arise. Python can move your mouse and type keystrokes at an incredible speed. In fact, it might be too fast for other programs to keep up with. Also, if something goes wrong but your program keeps moving the mouse around, it will be hard to tell what exactly the program is doing or how to recover from the problem. Like the enchanted brooms from Disney’s The Sorcerer’s Apprentice, which kept filling&mdashand then overfilling&mdashMickey’s tub with water, your program could get out of control even though it’s following your instructions perfectly. Stopping the program can be difficult if the mouse is moving around on its own, preventing you from clicking the Mu Editor window to close it. Fortunately, there are several ways to prevent or recover from GUI automation problems.
Pauses and Fail-Safes
If your program has a bug and you’re unable to use the keyboard and mouse to shut it down, you can use PyAutoGUI’s fail-safe feature. Quickly slide the mouse to one of the four corners of the screen. Every PyAutoGUI function call has a 10th-of-a-second delay after performing its action to give you enough time to move the mouse to a corner. If PyAutoGUI then finds that the mouse cursor is in a corner, it raises the pyautogui.FailSafeException exception. Non-PyAutoGUI instructions will not have this 10th-of-a-second delay.
If you find yourself in a situation where you need to stop your PyAutoGUI program, just slam the mouse toward a corner to stop it.
Shutting Down Everything by Logging Out
Perhaps the simplest way to stop an out-of-control GUI automation program is to log out, which will shut down all running programs. On Windows and Linux, the logout hotkey is CTRL-ALT-DEL. On macOS, it is -SHIFT-OPTION-Q. By logging out, you’ll lose any unsaved work, but at least you won’t have to wait for a full reboot of the computer.
Controlling Mouse Movement
In this section, you’ll learn how to move the mouse and track its position on the screen using PyAutoGUI, but first you need to understand how PyAutoGUI works with coordinates.
The mouse functions of PyAutoGUI use x- and y-coordinates. Figure 20-1 shows the coordinate system for the computer screen it’s similar to the coordinate system used for images, discussed in Chapter 19. The origin, where x and y are both zero, is at the upper-left corner of the screen. The x-coordinates increase going to the right, and the y-coordinates increase going down. All coordinates are positive integers there are no negative coordinates.
Figure 20-1: The coordinates of a computer screen with 1920×1080 resolution
Your resolution is how many pixels wide and tall your screen is. If your screen’s resolution is set to 1920×1080, then the coordinate for the upper-left corner will be (0, 0), and the coordinate for the bottom-right corner will be (1919, 1079).
The pyautogui.size() function returns a two-integer tuple of the screen’s width and height in pixels. Enter the following into the interactive shell:
>>> import pyautogui
>>> wh = pyautogui.size() # Obtain the screen resolution.
The pyautogui.size() function returns (1920, 1080) on a computer with a 1920×1080 resolution depending on your screen’s resolution, your return value may be different. The Size object returned by size() is a named tuple. Named tuples have numeric indexes, like regular tuples, and attribute names, like objects: both wh and wh.width evaluate to the width of the screen. (Named tuples are beyond the scope of this book. Just remember that you can use them the same way you use tuples.)
Moving the Mouse
Now that you understand screen coordinates, let’s move the mouse. The pyautogui.moveTo() function will instantly move the mouse cursor to a specified position on the screen. Integer values for the x- and y-coordinates make up the function’s first and second arguments, respectively. An optional duration integer or float keyword argument specifies the number of seconds it should take to move the mouse to the destination. If you leave it out, the default is 0 for instantaneous movement. (All of the duration keyword arguments in PyAutoGUI functions are optional.) Enter the following into the interactive shell:
>>> import pyautogui
>>> for i in range(10): # Move mouse in a square.
. pyautogui.moveTo(100, 100, duration=0.25)
. pyautogui.moveTo(200, 100, duration=0.25)
. pyautogui.moveTo(200, 200, duration=0.25)
. pyautogui.moveTo(100, 200, duration=0.25)
This example moves the mouse cursor clockwise in a square pattern among the four coordinates provided a total of 10 times. Each movement takes a quarter of a second, as specified by the duration=0.25 keyword argument. If you hadn’t passed a third argument to any of the pyautogui.moveTo() calls, the mouse cursor would have instantly teleported from point to point.
The pyautogui.move() function moves the mouse cursor relative to its current position. The following example moves the mouse in the same square pattern, except it begins the square from wherever the mouse happens to be on the screen when the code starts running:
>>> import pyautogui
>>> for i in range(10):
. pyautogui.move(100, 0, duration=0.25) # right
. pyautogui.move(0, 100, duration=0.25) # down
. pyautogui.move(-100, 0, duration=0.25) # left
. pyautogui.move(0, -100, duration=0.25) # up
The pyautogui.move() function also takes three arguments: how many pixels to move horizontally to the right, how many pixels to move vertically downward, and (optionally) how long it should take to complete the movement. A negative integer for the first or second argument will cause the mouse to move left or upward, respectively.
Getting the Mouse Position
You can determine the mouse’s current position by calling the pyautogui.position() function, which will return a Point named tuple of the mouse cursor’s x and y positions at the time of the function call. Enter the following into the interactive shell, moving the mouse around after each call:
>>> pyautogui.position() # Get current mouse position.
>>> pyautogui.position() # Get current mouse position again.
>>> p = pyautogui.position() # And again.
>>> p # The x-coordinate is at index 0.
>>> p.x # The x-coordinate is also in the x attribute.
Of course, your return values will vary depending on where your mouse cursor is.
Controlling Mouse Interaction
Now that you know how to move the mouse and figure out where it is on the screen, you’re ready to start clicking, dragging, and scrolling.
Clicking the Mouse
To send a virtual mouse click to your computer, call the pyautogui.click() method. By default, this click uses the left mouse button and takes place wherever the mouse cursor is currently located. You can pass x- and y-coordinates of the click as optional first and second arguments if you want it to take place somewhere other than the mouse’s current position.
If you want to specify which mouse button to use, include the button keyword argument, with a value of 'left' , 'middle' , or 'right' . For example, pyautogui.click(100, 150, button='left') will click the left mouse button at the coordinates (100, 150), while pyautogui.click(200, 250, button='right') will perform a right-click at (200, 250).
Enter the following into the interactive shell:
>>> import pyautogui
>>> pyautogui.click(10, 5) # Move mouse to (10, 5) and click.
You should see the mouse pointer move to near the top-left corner of your screen and click once. A full “click” is defined as pushing a mouse button down and then releasing it back up without moving the cursor. You can also perform a click by calling pyautogui.mouseDown() , which only pushes the mouse button down, and pyautogui.mouseUp() , which only releases the button. These functions have the same arguments as click() , and in fact, the click() function is just a convenient wrapper around these two function calls.
As a further convenience, the pyautogui.doubleClick() function will perform two clicks with the left mouse button, while the pyautogui.rightClick() and pyautogui.middleClick() functions will perform a click with the right and middle mouse buttons, respectively.
Dragging the Mouse
Dragging means moving the mouse while holding down one of the mouse buttons. For example, you can move files between folders by dragging the folder icons, or you can move appointments around in a calendar app.
PyAutoGUI provides the pyautogui.dragTo() and pyautogui.drag() functions to drag the mouse cursor to a new location or a location relative to its current one. The arguments for dragTo() and drag() are the same as moveTo() and move() : the x-coordinate/horizontal movement, the y-coordinate/vertical movement, and an optional duration of time. (macOS does not drag correctly when the mouse moves too quickly, so passing a duration keyword argument is recommended.)
To try these functions, open a graphics-drawing application such as MS Paint on Windows, Paintbrush on macOS, or GNU Paint on Linux. (If you don’t have a drawing application, you can use the online one at https://sumopaint.com/.) I will use PyAutoGUI to draw in these applications.
With the mouse cursor over the drawing application’s canvas and the Pencil or Brush tool selected, enter the following into a new file editor window and save it as spiralDraw.py:
import pyautogui, time
? pyautogui.click() # Click to make the window active.
distance = 300
change = 20
while distance > 0:
? pyautogui.drag(distance, 0, duration=0.2) # Move right.
? distance = distance &ndash change
? pyautogui.drag(0, distance, duration=0.2) # Move down.
? pyautogui.drag(-distance, 0, duration=0.2) # Move left.
distance = distance &ndash change
pyautogui.drag(0, -distance, duration=0.2) # Move up.
When you run this program, there will be a five-second delay ? for you to move the mouse cursor over the drawing program’s window with the Pencil or Brush tool selected. Then spiralDraw.py will take control of the mouse and click to make the drawing program’s window active ? . The active window is the window that currently accepts keyboard input, and the actions you take&mdashlike typing or, in this case, dragging the mouse&mdashwill affect that window. The active window is also known as the focused or foreground window. Once the drawing program is active, spiralDraw.py draws a square spiral pattern like the one on the left of Figure 20-2. While you can also create a square spiral image by using the Pillow module discussed in Chapter 19, creating the image by controlling the mouse to draw it in MS Paint lets you make use of this program’s various brush styles, like in Figure 20-2 on the right, as well as other advanced features, like gradients or the fill bucket. You can preselect the brush settings yourself (or have your Python code select these settings) and then run the spiral-drawing program.
Figure 20-2: The results from the pyautogui.drag() example, drawn with MS Paint’s different brushes
The distance variable starts at 200 , so on the first iteration of the while loop, the first drag() call drags the cursor 200 pixels to the right, taking 0.2 seconds ? . distance is then decreased to 195 ? , and the second drag() call drags the cursor 195 pixels down ? . The third drag() call drags the cursor &ndash195 horizontally (195 to the left) ? , distance is decreased to 190, and the last drag() call drags the cursor 190 pixels up. On each iteration, the mouse is dragged right, down, left, and up, and distance is slightly smaller than it was in the previous iteration. By looping over this code, you can move the mouse cursor to draw a square spiral.
You could draw this spiral by hand (or rather, by mouse), but you’d have to work slowly to be so precise. PyAutoGUI can do it in a few seconds!
At the time of this writing, PyAutoGUI can’t send mouse clicks or keystrokes to certain programs, such as antivirus software (to prevent viruses from disabling the software) or video games on Windows (which use a different method of receiving mouse and keyboard input). You can check the online documentation at https://pyautogui.readthedocs.io/ to see if these features have been added.
Scrolling the Mouse
The final PyAutoGUI mouse function is scroll() , which you pass an integer argument for how many units you want to scroll the mouse up or down. The size of a unit varies for each operating system and application, so you’ll have to experiment to see exactly how far it scrolls in your particular situation. The scrolling takes place at the mouse cursor’s current position. Passing a positive integer scrolls up, and passing a negative integer scrolls down. Run the following in Mu Editor’s interactive shell while the mouse cursor is over the Mu Editor window:
You’ll see Mu scroll upward if the mouse cursor is over a text field that can be scrolled up.
Planning Your Mouse Movements
One of the difficulties of writing a program that will automate clicking the screen is finding the x- and y-coordinates of the things you’d like to click. The pyautogui.mouseInfo() function can help you with this.
The pyautogui.mouseInfo() function is meant to be called from the interactive shell, rather than as part of your program. It launches a small application named MouseInfo that’s included with PyAutoGUI. The window for the application looks like Figure 20-3.
Figure 20-3: The MouseInfo application’s window
Enter the following into the interactive shell:
>>> import pyautogui
This makes the MouseInfo window appear. This window gives you information about the mouse’s cursor current position, as well the color of the pixel underneath the mouse cursor, as a three-integer RGB tuple and as a hex value. The color itself appears in the color box in the window.
To help you record this coordinate or pixel information, you can click one of the eight Copy or Log buttons. The Copy All, Copy XY, Copy RGB, and Copy RGB Hex buttons will copy their respective information to the clipboard. The Log All, Log XY, Log RGB, and Log RGB Hex buttons will write their respective information to the large text field in the window. You can save the text in this log text field by clicking the Save Log button.
By default, the 3 Sec. Button Delay checkbox is checked, causing a three-second delay between clicking a Copy or Log button and the copying or logging taking place. This gives you a short amount of time in which to click the button and then move the mouse into your desired position. It may be easier to uncheck this box, move the mouse into position, and press the F1 to F8 keys to copy or log the mouse position. You can look at the Copy and Log menus at the top of the MouseInfo window to find out which key maps to which buttons.
For example, uncheck the 3 Sec. Button Delay, then move the mouse around the screen while pressing the F6 button, and notice how the x- and y-coordinates of the mouse are recorded in the large text field in the middle of the window. You can later use these coordinates in your PyAutoGUI scripts.
For more information on MouseInfo, review the complete documentation at https://mouseinfo.readthedocs.io/.
Working with the Screen
Your GUI automation programs don’t have to click and type blindly. PyAutoGUI has screenshot features that can create an image file based on the current contents of the screen. These functions can also return a Pillow Image object of the current screen’s appearance. If you’ve been skipping around in this book, you’ll want to read Chapter 17 and install the pillow module before continuing with this section.
On Linux computers, the scrot program needs to be installed to use the screenshot functions in PyAutoGUI. In a Terminal window, run sudo apt-get install scrot to install this program. If you’re on Windows or macOS, skip this step and continue with the section.
Getting a Screenshot
To take screenshots in Python, call the pyautogui.screenshot() function. Enter the following into the interactive shell:
>>> import pyautogui
>>> im = pyautogui.screenshot()
The im variable will contain the Image object of the screenshot. You can now call methods on the Image object in the im variable, just like any other Image object. Chapter 19 has more information about Image objects.
Analyzing the Screenshot
Say that one of the steps in your GUI automation program is to click a gray button. Before calling the click() method, you could take a screenshot and look at the pixel where the script is about to click. If it’s not the same gray as the gray button, then your program knows something is wrong. Maybe the window moved unexpectedly, or maybe a pop-up dialog has blocked the button. At this point, instead of continuing&mdashand possibly wreaking havoc by clicking the wrong thing&mdashyour program can “see” that it isn’t clicking the right thing and stop itself.
You can obtain the RGB color value of a particular pixel on the screen with the pixel() function. Enter the following into the interactive shell:
>>> import pyautogui
>>> pyautogui.pixel((0, 0))
(176, 176, 175)
>>> pyautogui.pixel((50, 200))
(130, 135, 144)
Pass pixel() a tuple of coordinates, like (0, 0) or (50, 200), and it’ll tell you the color of the pixel at those coordinates in your image. The return value from pixel() is an RGB tuple of three integers for the amount of red, green, and blue in the pixel. (There is no fourth value for alpha, because screenshot images are fully opaque.)
PyAutoGUI’s pixelMatchesColor() function will return True if the pixel at the given x- and y-coordinates on the screen matches the given color. The first and second arguments are integers for the x- and y-coordinates, and the third argument is a tuple of three integers for the RGB color the screen pixel must match. Enter the following into the interactive shell:
>>> import pyautogui
? >>> pyautogui.pixel((50, 200))
(130, 135, 144)
? >>> pyautogui.pixelMatchesColor(50, 200, (130, 135, 144))
? >>> pyautogui.pixelMatchesColor(50, 200, (255, 135, 144))
After using pixel() to get an RGB tuple for the color of a pixel at specific coordinates ? , pass the same coordinates and RGB tuple to pixelMatchesColor() ? , which should return True . Then change a value in the RGB tuple and call pixelMatchesColor() again for the same coordinates ? . This should return false . This method can be useful to call whenever your GUI automation programs are about to call click() . Note that the color at the given coordinates must exactly match. If it is even slightly different&mdashfor example, (255, 255, 254) instead of (255, 255, 255) &mdashthen pixelMatchesColor() will return False .
But what if you do not know beforehand where PyAutoGUI should click? You can use image recognition instead. Give PyAutoGUI an image of what you want to click, and let it figure out the coordinates.
For example, if you have previously taken a screenshot to capture the image of a Submit button in submit.png, the locateOnScreen() function will return the coordinates where that image is found. To see how locateOnScreen() works, try taking a screenshot of a small area on your screen then save the image and enter the following into the interactive shell, replacing 'submit.png' with the filename of your screenshot:
>>> import pyautogui
>>> b = pyautogui.locateOnScreen('submit.png')
Box(left=643, top=745, width=70, height=29)
The Box object is a named tuple that locateOnScreen() returns and has the x-coordinate of the left edge, the y-coordinate of the top edge, the width, and the height for the first place on the screen the image was found. If you’re trying this on your computer with your own screenshot, your return value will be different from the one shown here.
If the image cannot be found on the screen, locateOnScreen() returns None . Note that the image on the screen must match the provided image perfectly in order to be recognized. If the image is even a pixel off, locateOnScreen() raises an ImageNotFoundException exception. If you’ve changed your screen resolution, images from previous screenshots might not match the images on your current screen. You can change the scaling in the display settings of your operating system, as shown in Figure 20-4.
Figure 20-4: The scale display settings in Windows 10 (left) and macOS (right)
If the image can be found in several places on the screen, locateAllOnScreen() will return a Generator object. Generators are beyond the scope of this book, but you can pass them to list() to return a list of four-integer tuples. There will be one four-integer tuple for each location where the image is found on the screen. Continue the interactive shell example by entering the following (and replacing 'submit.png' with your own image filename):
[(643, 745, 70, 29), (1007, 801, 70, 29)]
Each of the four-integer tuples represents an area on the screen. In the example above, the image appears in two locations. If your image is only found in one area, then using list() and locateAllOnScreen() returns a list containing just one tuple.
Once you have the four-integer tuple for the specific image you want to select, you can click the center of this area by passing the tuple to click() . Enter the following into the interactive shell:
>>> pyautogui.click((643, 745, 70, 29))
As a shortcut, you can also pass the image filename directly to the click() function:
The moveTo() and dragTo() functions also accept image filename arguments. Remember locateOnScreen() raises an exception if it can’t find the image on the screen, so you should call it from inside a try statement:
location = pyautogui.locateOnScreen('submit.png')
print('Image could not be found.')
Without the try and except statements, the uncaught exception would crash your program. Since you can’t be sure that your program will always find the image, it’s a good idea to use the try and except statements when calling locateOnScreen() .
Getting Window Information
Image recognition is a fragile way to find things on the screen if a single pixel is a different color, then pyautogui.locateOnScreen() won’t find the image. If you need to find where a particular window is on the screen, it’s faster and more reliable to use PyAutoGUI’s window features.
As of version 0.9.46, PyAutoGUI’s window features work only on Windows, not on macOS or Linux. These features come from PyAutoGUI’s inclusion of the PyGetWindow module.
Obtaining the Active Window
The active window on your screen is the window currently in the foreground and accepting keyboard input. If you’re currently writing code in the Mu Editor, the Mu Editor’s window is the active window. Of all the windows on your screen, only one will be active at a time.
In the interactive shell, call the pyautogui.getActiveWindow() function to get a Window object (technically a Win32Window object when run on Windows).
Once you have that Window object, you can retrieve any of the object’s attributes, which describe its size, position, and title:
left, right, top, bottom A single integer for the x- or y-coordinate of the window’s side
topleft, topright, bottomleft, bottomright A named tuple of two integers for the (x, y) coordinates of the window’s corner
midleft, midright, midleft, midright A named tuple of two integers for the (x, y) coordinate of the middle of the window’s side
width, height A single integer for one of the window’s dimensions, in pixels
size A named tuple of two integers for the (width, height) of the window
area A single integer representing the area of the window, in pixels
center A named tuple of two integers for the (x, y) coordinate of the window’s center
centerx, centery A single integer for the x- or y-coordinate of the window’s center
box A named tuple of four integers for the (left, top, width, height) measurements of the window
title A string of the text in the title bar at the top of the window
To get the window’s position, size, and title information from the window object, for example, enter the following into the interactive shell:
>>> import pyautogui
>>> fw = pyautogui.getActiveWindow()
'<Win32Window left="500", top="300",,, title="Mu 1.0.1 &ndash test1.py">'
'Mu 1.0.1 &ndash test1.py'
>>> fw.left, fw.top, fw.right, fw.bottom
(500, 300, 2070, 1208)
>>> pyautogui.click(fw.left + 10, fw.top + 20)
You can now use these attributes to calculate precise coordinates within a window. If you know that a button you want to click is always 10 pixels to the right of and 20 pixels down from the window’s top-left corner, and the window’s top-left corner is at screen coordinates (300, 500), then calling pyautogui.click(310, 520) (or pyautogui.click(fw.left + 10, fw.top + 20) if fw contains the Window object for the window) will click the button. This way, you won’t have to rely on the slower, less reliable locateOnScreen() function to find the button for you.
Other Ways of Obtaining Windows
While getActiveWindow() is useful for obtaining the window that is active at the time of the function call, you’ll need to use some other function to obtain Window objects for the other windows on the screen.
The following four functions return a list of Window objects. If they’re unable to find any windows, they return an empty list:
pyautogui.getAllWindows() Returns a list of Window objects for every visible window on the screen.
pyautogui.getWindowsAt(x, y) Returns a list of Window objects for every visible window that includes the point (x, y).
pyautogui.getWindowsWithTitle(title) Returns a list of Window objects for every visible window that includes the string title in its title bar.
pyautogui.getActiveWindow() Returns the Window object for the window that is currently receiving keyboard focus.
PyAutoGUI also has a pyautogui.getAllTitles() function, which returns a list of strings of every visible window.
Windows attributes can do more than just tell you the size and position of the window. You can also set their values in order to resize or move the window. For example, enter the following into the interactive shell:
>>> import pyautogui
>>> fw = pyautogui.getActiveWindow()
? >>> fw.width # Gets the current width of the window.
? >>> fw.topleft # Gets the current position of the window.
? >>> fw.width = 1000 # Resizes the width.
? >>> fw.topleft = (800, 400) # Moves the window.
First, we use the Window object’s attributes to find out information about the window’s size ? and position ? . After calling these functions in Mu Editor, the window should move ? and become narrower ? , as in Figure 20-5.
Figure 20-5: The Mu Editor window before (top) and after (bottom) using the Window object attributes to move and resize it
You can also find out and change the window’s minimized, maximized, and activated states. Try entering the following into the interactive shell:
>>> import pyautogui
>>> fw = pyautogui.getActiveWindow()
? >>> fw.isMaximized # Returns True if window is maximized.
? >>> fw.isMinimized # Returns True if window is minimized.
? >>> fw.isActive # Returns True if window is the active window.
? >>> fw.maximize() # Maximizes the window.
? >>> fw.restore() # Undoes a minimize/maximize action.
? >>> fw.minimize() # Minimizes the window.
>>> import time
>>> # Wait 5 seconds while you activate a different window:
? >>> time.sleep(5) fw.activate()
? >>> fw.close() # This will close the window you're typing in.
The isMaximized ? , isMinimized ? , and isActive ? attributes contain Boolean values that indicate whether the window is currently in that state. The maximize() ? , minimize() ? , activate() ? , and restore() ? methods change the window’s state. After you maximize or minimize the window with maximize() or minimize() , the restore() method will restore the window to its former size and position.
The close() method ? will close a window. Be careful with this method, as it may bypass any message dialogs asking you to save your work before quitting the application.
The complete documentation for PyAutoGUI’s window-controlling feature can be found at https://pyautogui.readthedocs.io/. You can also use these features separately from PyAutoGUI with the PyGetWindow module, documented at https://pygetwindow.readthedocs.io/.
Controlling the Keyboard
PyAutoGUI also has functions for sending virtual keypresses to your computer, which enables you to fill out forms or enter text into applications.
Sending a String from the Keyboard
The pyautogui.write() function sends virtual keypresses to the computer. What these keypresses do depends on what window is active and what text field has focus. You may want to first send a mouse click to the text field you want in order to ensure that it has focus.
As a simple example, let’s use Python to automatically type the words Hello, world! into a file editor window. First, open a new file editor window and position it in the upper-left corner of your screen so that PyAutoGUI will click in the right place to bring it into focus. Next, enter the following into the interactive shell:
>>> pyautogui.click(100, 200) pyautogui.write('Hello, world!')
Notice how placing two commands on the same line, separated by a semicolon, keeps the interactive shell from prompting you for input between running the two instructions. This prevents you from accidentally bringing a new window into focus between the click() and write() calls, which would mess up the example.
Python will first send a virtual mouse click to the coordinates (100, 200), which should click the file editor window and put it in focus. The write() call will send the text Hello, world! to the window, making it look like Figure 20-6. You now have code that can type for you!
Figure 20-6: Using PyAutogGUI to click the file editor window and type Hello, world! into it
By default, the write() function will type the full string instantly. However, you can pass an optional second argument to add a short pause between each character. This second argument is an integer or float value of the number of seconds to pause. For example, pyautogui.write('Hello, world!', 0.25) will wait a quarter-second after typing H, another quarter-second after e, and so on. This gradual typewriter effect may be useful for slower applications that can’t process keystrokes fast enough to keep up with PyAutoGUI.
For characters such as A or !, PyAutoGUI will automatically simulate holding down the SHIFT key as well.
Not all keys are easy to represent with single text characters. For example, how do you represent SHIFT or the left arrow key as a single character? In PyAutoGUI, these keyboard keys are represented by short string values instead: 'esc' for the ESC key or 'enter' for the ENTER key.
Instead of a single string argument, a list of these keyboard key strings can be passed to write() . For example, the following call presses the A key, then the B key, then the left arrow key twice, and finally the X and Y keys:
Because pressing the left arrow key moves the keyboard cursor, this will output XYab. Table 20-1 lists the PyAutoGUI keyboard key strings that you can pass to write() to simulate pressing any combination of keys.
You can also examine the pyautogui.KEYBOARD_KEYS list to see all possible keyboard key strings that PyAutoGUI will accept. The 'shift' string refers to the left SHIFT key and is equivalent to 'shiftleft' . The same applies for 'ctrl' , 'alt' , and 'win' strings they all refer to the left-side key.
Table 20-1: PyKeyboard Attributes
Keyboard key string
'a' , 'b' , 'c' , 'A' , 'B' , 'C' , '1' , '2' , '3' , '!' , '@' , '#' , and so on