pyrap-devel Mailing List for pyrap
Status: Planning
Brought to you by:
jcorbett
You can subscribe to this list here.
2005 |
Jan
|
Feb
|
Mar
|
Apr
(2) |
May
(1) |
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
---|---|---|---|---|---|---|---|---|---|---|---|---|
2006 |
Jan
|
Feb
(6) |
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: <jco...@us...> - 2006-02-24 23:56:17
|
Revision: 5 Author: jcorbett Date: 2006-02-24 15:56:13 -0800 (Fri, 24 Feb 2006) ViewCVS: http://svn.sourceforge.net/pyrap/?rev=5&view=rev Log Message: ----------- Undoing other minor change Modified Paths: -------------- pyrap/pyrap.wpr Modified: pyrap/pyrap.wpr =================================================================== --- pyrap/pyrap.wpr 2006-02-24 23:46:56 UTC (rev 4) +++ pyrap/pyrap.wpr 2006-02-24 23:56:13 UTC (rev 5) @@ -1,6 +1,5 @@ #!wing #!version=2.0 - ################################################################## # Wing IDE project file # ################################################################## This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jco...@us...> - 2006-02-24 23:46:58
|
Revision: 4 Author: jcorbett Date: 2006-02-24 15:46:56 -0800 (Fri, 24 Feb 2006) ViewCVS: http://svn.sourceforge.net/pyrap/?rev=4&view=rev Log Message: ----------- made a small change to see if notification email is working Modified Paths: -------------- pyrap/pyrap.wpr Modified: pyrap/pyrap.wpr =================================================================== --- pyrap/pyrap.wpr 2006-02-24 23:35:11 UTC (rev 3) +++ pyrap/pyrap.wpr 2006-02-24 23:46:56 UTC (rev 4) @@ -1,5 +1,6 @@ #!wing #!version=2.0 + ################################################################## # Wing IDE project file # ################################################################## This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jco...@us...> - 2006-02-24 23:35:14
|
Revision: 3 Author: jcorbett Date: 2006-02-24 15:35:11 -0800 (Fri, 24 Feb 2006) ViewCVS: http://svn.sourceforge.net/pyrap/?rev=3&view=rev Log Message: ----------- Property Changed: ---------------- pyrap/doc/html/ pyrap/doc/pdf/ Property changes on: pyrap/doc/html ___________________________________________________________________ Name: svn:ignore + ignore doc dirs Property changes on: pyrap/doc/pdf ___________________________________________________________________ Name: svn:ignore + ignore pdf doc dir This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jco...@us...> - 2006-02-24 23:18:22
|
Revision: 2 Author: jcorbett Date: 2006-02-24 15:18:15 -0800 (Fri, 24 Feb 2006) ViewCVS: http://svn.sourceforge.net/pyrap/?rev=2&view=rev Log Message: ----------- forgot to add the actual python files ;) Added Paths: ----------- pyrap/pyrap/__init__.py pyrap/pyrap/imagerec.py pyrap/pyrap/project.py pyrap/pyrap/session.py Added: pyrap/pyrap/__init__.py =================================================================== --- pyrap/pyrap/__init__.py (rev 0) +++ pyrap/pyrap/__init__.py 2006-02-24 23:18:15 UTC (rev 2) @@ -0,0 +1,4 @@ + +__all__ = ['project', 'session', 'imagerec'] + +__docformat__ = "javadoc" \ No newline at end of file Property changes on: pyrap/pyrap/__init__.py ___________________________________________________________________ Name: svn:executable + * Name: svn:mime-type + text/plain Name: svn:eol-style + native Added: pyrap/pyrap/imagerec.py =================================================================== --- pyrap/pyrap/imagerec.py (rev 0) +++ pyrap/pyrap/imagerec.py 2006-02-24 23:18:15 UTC (rev 2) @@ -0,0 +1,123 @@ +"""Image Recognition Module. Here you will find functions that will allow you +to find images on the X11 screen. Although the ability to provide this +capability isn't coded here in python, it is no less powerful. visgrep command +from <a href="http://hoopajoo.net/projects/xautomation.html">xautomation +</a> provides the ability to find one image inside another, this module turns +that command line program into an automation framewok.""" + +__docformat__ = "javadoc" + +import subprocess +import gc +import session +import types +import os.path +import tempfile +import atexit +import re + +from time import time + + +class ImageRecognitionException(Exception): + """This class is for errors related to recognizing an image on the X11 Screen. + You might get this exception if you said there should only be one of the image + on the screen, but more than one is detected. Also if any programs that this + module depends on is missing, or if the image your looking for isn't a png (a + major no-no).""" + pass + +class SearchPattern: + """This represents the image your looking for on the X11 display. You will + need to pass in a .png file to the constructor. This is then turned into a + pattern that <a href="http://hoopajoo.net/projects/xautomation.html"> + xautomation's visgrep</a> can use to search for on the screen. + @cvar DEFAULT_TIMEOUT The default amount of time to look for an image on the + screen in seconds. + @type DEFAULT_TIMEOUT int + @cvar _tempdir The directory to store all the .pat images in, cleanup is done + at exit. + @type _tempdir str + @ivar _patfile The pattern file that visgrep uses to search for, created on + initialization of the object. + @type _patfile str""" + + DEFAULT_TIMEOUT = 60 + + _visgrepRE = re.compile(r'^(\d+),(\d+)\s') + + _tempdir = tempfile.mkdtemp("irec") + + def __init__(self, image): + """Create a new image search pattern. Pass in the path to a png file. + @param image The path on the file system to a png image to look for + @type image str + @raise pyrap.imagerec.ImageRecognitionException Raises exception when the + image passed in doesn't exist, + when it isn't a png, or when + there is an error converting + it to a .pat (see visgrep + manpage).""" + assert(isinstance(image, types.StringTypes)) + if not os.path.exists(image): + raise ImageRecognitionException, "Path [%s] does not exist." % (image) + (fileHandle, self._patfile) = tempfile.mkstemp(suffix=".pat", dir=self._tempdir) + os.close(fileHandle) + retcode = subprocess.call(args=["/bin/bash","-c", "png2pat %s >%s" % (image, self._patfile)]) + if retcode != 0: + raise ImageRecognitionException, "png2pat of file [%s] to file [%s] failed!" % (image, self._patfile) + if os.path.getsize(self._patfile) <= 0: + raise ImageRecognitionException, "Size of patfile [%s] is [%d], it came from png file [%s] size [%d]." % (self._patfile, os.path.getsize(self._patfile), image, os.path.getsize(image)) + atexit.register(self._cleanup) + + + def findOnScreen(self, xsession, timeout=DEFAULT_TIMEOUT): + """Find the image on the screen. This method works by searching for the + image on the screen, until timeout occurs. If timeout occurs before a match + is made None is return. However if a match is found within the timeout + period, all the coordinates of the specified instance are returned. + @param xsession The X11Session object to look for the image on. + @type xsession pyrap.session.X11Session + @param timeout The amount in seconds to keep looking for the image. + @type timeout int + @return None (if no matches were found), or a tuple containing the + coordinates (x,y) in the screen for each match. + ie ((10, 589)(895, 1478))""" + assert(isinstance(xsession, session.X11Session)) + assert(isinstance(timeout, types.IntType)) + startTime = time() + endTime = startTime + timeout + coordinates = [] + ssFileName = os.path.join(self._tempdir, "shot.png") + while time() < endTime: + print "Before screen shot.\n" + screenShot = xsession.getScreenShot() + print "After screen shot.\n" + screenShot.save(ssFileName, "png") + print "After screen shot save.\n" + visgrep = subprocess.Popen(["visgrep", ssFileName, self._patfile], stdout=subprocess.PIPE) + retcode = visgrep.wait() + print "After visgrep.\n" + if retcode == 1: + for line in visgrep.stdout: + lineMatch = self._visgrepRE.match(line) + if lineMatch is not None: + coordinates.append((int(lineMatch.group(1)), int(lineMatch.group(2)))) + del lineMatch + if len(coordinates) > 0: + return tuple(coordinates) + print "After line processing.\n" + del screenShot + del visgrep + print "About to collect garbage.\n" + gc.collect() + print "After Garbage collection.\n" + + return None + + def _cleanup(self): + if os.path.exists(self._patfile): + os.unlink(self._patfile) + if len(os.listdir(self._tempdir)) == 0: + os.rmdir(self._tempdir) + Property changes on: pyrap/pyrap/imagerec.py ___________________________________________________________________ Name: svn:executable + * Name: svn:mime-type + text/plain Name: svn:eol-style + native Added: pyrap/pyrap/project.py =================================================================== --- pyrap/pyrap/project.py (rev 0) +++ pyrap/pyrap/project.py 2006-02-24 23:18:15 UTC (rev 2) @@ -0,0 +1,193 @@ +"""Features of pyrap relating to projects, including testcases. You shouldn't +need to create a instance of TestCase directly, instead use the +{@link pyrap.project.load load()} method to create an instance. This makes +working with the image recognition module much easier, and more intuitive. +@author Jason Corbett +@version 1.0""" + +__docformat__ = "javadoc" + +import sys +import os.path +import UserDict +import ConfigParser +import imagerec, session +import logging, logging.config + +def load(directory=os.path.abspath(os.path.dirname(sys.argv[0])), filename="project.ini", runtime="var.ini"): + """Load an instance of {@link pyrap.project.TestCase TestCase} using settings + in a project.ini. By default use the directory of the calling script (argv[0]) + and project.ini as the project file to load. Dynamic variables should be + loaded through var.ini in the same directory. + @param directory The directory that holds the test case files to load. + @type directory str + @param filename The name of the main project ini file (holds project settings) + @type filename str + @param runtime The name of the runtime variables file (additional to project + settings). + @type runtime str + @return Instance of Testcase that has all images registered and is ready to + run, or None on error. + @rtype pyrap.project.TestCase""" + project_file = os.path.join(directory, filename) + runtime_file = os.path.join(directory, runtime) + default_project_configfile = os.path.join(os.path.abspath(os.path.dirname(__file__)), "project-defaults.ini") + default_logging_configfile = os.path.join(os.path.abspath(os.path.dirname(__file__)), "logging-defaults.ini") + + options = ConfigParser.SafeConfigParser() + options.read([default_project_configfile, project_file, runtime_file]) + + custom_logging_configfile = os.path.join(directory, options.get("Test Case", "logging.configfile")) + + if options.get("Test Case", "logging") == "custom" and os.path.exists(custom_logging_configfile): + logging.config.fileConfig(custom_logging_configfile, {"tcroot": directory}) + else: + logging.config.fileConfig(default_logging_configfile, {"tcroot": directory}) + + pyrap_logger = logging.getLogger("pyrap.project.load") + tc_logger = logging.getLogger("testcase.%s" % (options.get("Test Case", "name"))) + + if options.has_option("Test Case", "logging.pyrap.level"): + logging.getLogger("pyrap").setLevel(eval("logging.%s" % (options.get("Test Case", "logging.pyrap.level")))) + + if options.has_option("Test Case", "logging.testcase.level"): + logging.getLogger("testcase").setLevel(eval("logging.%s" % (options.get("Test Case", "logging.testcase.level")))) + + all_requisites_found = True + for requisite in ["Test Case", "X11 Session", "Images"]: + if not options.has_section(requisite): + all_requisites_found = False + tc_logger.critical("Project [%s] does not have section [%s] in the ini file [%s].", options.get("Test Case", "name"), requisite, project_file) + if not all_requisites_found: + return None + + + + + + +class TestCase(UserDict.UserDict): + """Uses parts of {@link pyrap.session.X11Session X11Session} to create + a testcase. Settings should be a ConfigParser object. Possible settings are: + <ul> + <li>Section <b>Test Case</b> + <ul> + <li><code>name = My Test Case</code> + <p>This name is used in logging and the reports generated. It's + important to give a descriptive name, that is also unique (for + clarity).</p> + </li> + <li><code>logging = normal</code> + <p>logging for pyrap. There is a pre-configured logging setup, + putting all logs into a logs/ directory, but you can completely + customize the logging. Valid values are: "normal", "custom", or + "semi normal". "normal" means no changes. "custom" means that + you want to specify a logging config file (in python looging + <a href="http://www.python.org/doc/2.4.1/lib/logging-config-fileformat.html"> + configuration syntax</a>). "semi normal" means that you want the + normal configuration, but with some customizations (options listed + below).</p> + </li> + <li><code>logging.configfile = logging.ini</code> + <p>If and only if you specified "custom" as the type of logging + does this parameter get evaluated. It should point to a file + (relative to the root of the test directory) that contains your + logging configuration.</p> + </li> + <li><code>logging.pyrap.level = DEBUG</code> + <p>If and only if you specified "semi normal" as the type of logging + does this parameter get evaluated. This is the logging level for + pyrap internals, not for the testcase itself. It should be a + valid logging level (such as <code>CRITICAL, ERROR, WARNING, INFO, + DEBUG, NOTSET</code>).</p> + <p>Default is <code>WARNING</code></p> + </li> + <li><code>logging.testcase.level = DEBUG</code> + <p>If and only if you specified "semi normal" as the type of logging + does this parameter get evaluated. This is the logging level for + the testcase, not for the pyrap internals. If you're unsure what + you want, this is probably it, pyrap internals deals with what's + happening in pyrap itself. It should be a valid logging level + (such as <code>CRITICAL, ERROR, WARNING, INFO, DEBUG, NOTSET</code> + ).</p> + <p>Default is <code>INFO</code></p> + </li> + </ul> + </li> + <li>Section <b>X11 Session</b> + <ul> + <li><code>resolution.x = 1024</code> + <p>The width of the X11 Screen to create, default is + <code>1024</code></p> + </li> + <li><code>resolution.y = 768</code> + <p>The height of the X11 Screen to create, default is + <code>768</code></p> + </li> + <li><code>color depth = 16</code> + <p>The color depth to use for the X Server. <b>IMPORTANT:</b> + please note that you don't want to use a different depth other + than what you used to record your test case. If the png images + you captured were in a different color depth, image recognition + will not work.</p> + <p>Default is <code>16</code></p> + </li> + </ul> + </li> + <li>Section <b>Images</b><br/> + example: <code>name = image file name</code> + <p>This should be a mapping between the names you want to use in your + scripts (for example: "Start Menu") and the actual file names of the + images (for example: "images/start.png", or "images/984810238.png"). + For each image listed here a {@link pyrap.imagerec.SearchPattern + SearchPattern} object will be created on initialization, and held for + use in the test case. Filenames should be relative to the root of the + TestCase directory</p> + </li> + <li>Section <b>Variables</b><br/> + <p>All key value pairs in this section will be put into this classes + dictionary properties. That means that if you have an entry in your + ini file for Variables, and in it you have the entry <code>Foo = Bar</code> + , then you can reference it by <code>tcinstance["Foo"]</code> and + you will get Bar in return.</p> + </li> + </ul>""" + + def __init__(self, settings, rootDirectory): + """Create an instance of TestCase with the settings passed in. + @param settings ConfigParser object containing settings for this Test Case. + @type settings {@link ConfigParser.ConfigParser ConfigParser} + @param rootDirectory The root of the Test Case + @type rootDirectory str""" + UserDict.UserDict.__init__(self) + self.logger = logging.getLogger("pyrap.project.TestCase") + assert(isinstance(settings, ConfigParser.ConfigParser)) + if settings.has_section("Variables"): + self.logger.debug("Going to add all entries from Variables section to project.") + for key, value in settings.items("Variables"): + self.logger.debug("Adding variable entry to project: %s = %s", key, value) + self[key] = value + self.searchPatterns = {} + self.logger.debug("Creating SearchPattern objects from Images section in ini file.") + for name, filename in settings.items("Images"): + try: + if os.path.exists(os.path.join(rootDirectory, filename)): + self.logger.debug("Creating SearchPattern object for entry: %s = %s, fullpath name: %s", name, filename, os.path.join(rootDirectory, filename)) + self.searchPatterns[name] = imagerec.SearchPattern(os.path.join(rootDirectory, filename)) + self.logger.debug("SearchPattern with the name of %s, was successfully created.", name) + else: + self.logger.error("File does not exist for image entry: %s = %s", name, filename) + continue + except imagerec.ImageRecognitionException, error: + self.logger.error("Error creating SearchPattern, will be unavailable, entry: %s = %s, error: ", name, filename, error) + continue + self.logger.debug("Done creating SearchPattern objects.") + + xres = settings.getint("X11 Session", "resolution.x") + yres = settings.getint("X11 Session", "resolution.y") + depth = settings.getint("X11 Session", "depth") + + self.logger.debug("Creating X11 Session with resolution %dx%d and depth %d", xres, yres, depth) + self.xs = session.X11Session(xres, yres, depth) + self.logger.debug("Created X11 Session, DISPLAY=:%d", self.xs.display) + Property changes on: pyrap/pyrap/project.py ___________________________________________________________________ Name: svn:executable + * Name: svn:mime-type + text/plain Name: svn:eol-style + native Added: pyrap/pyrap/session.py =================================================================== --- pyrap/pyrap/session.py (rev 0) +++ pyrap/pyrap/session.py 2006-02-24 23:18:15 UTC (rev 2) @@ -0,0 +1,429 @@ +"""The Session Module contains functions and classes for running a Test Session. +<p>Sessions consist of at least 1 program running in a X11 virtual server (Xvfb). +Contained in this module is variables for key bindings (special keys), and +the TestSession class that has methods relating to the running session.</p> + +@author Jason Corbett +@version 1.0 + +@var SpecialKeys Special Keys holds all the keys that you would want to simulate + pressing in an X11 Session. You can use these keys with the + X11Session Class, or with KeyCombination Class (to pass + eventually to X11Session). Keys available are: + <ul> + <li>Home Key</li> + <li>Arrow Keys (Up, Down, Left, and Right)</li> + <li>PageUp and PageDown Keys</li> + <li>End Key</li> + <li>Return Key (aka Enter)</li> + <li>Tab Key</li> + <li>Escape Key</li> + <li>Delete Key</li> + <li>Modifier Keys like Shift, Control, Alt, and Meta (Windows)</li> + <li>Backspace Key</li> + </ul> + <p>Keys that have Left and Right ones on the keyboard can be + accessed with or without the Left and Right prefix (example: + SpecialKeys.LeftShift = SpecialKeys.Shift). Left and Right + prefixes should come first before the name of the key. You + should be able to acess the keys with the names above, and case + shouldn't matter. If you really care, you can look at + {@link pyrap.session.SpecialKeyClass#specialKeys specialKeys} + variable of the SpecialKeyClass.</p> +@type SpecialKeys pyrap.session.SpecialKeyClass +""" + +import types +import os +import tempfile +import atexit +import subprocess +import signal +import gtk.gdk + +# The following is required for epydoc to parse comments correctly +__docformat__ = "javadoc" + +class MouseClickType: + """This class is pretty basic, however several static methods exist to allow + you to create specific, common used instances of this class. For instance, + you might need to double click. Rather than creating a separate instance of + MouseClickType by doing: <code>MouseClickType(1,2)</code>, which isn't readable + to anyone reading your code, use should use the DoubleClick method which does + the same thing, it should also cache the instance creation so that you don't + have to create multiple instances of the same value. + @ivar commands An array of strings that holds the commands to send to xte. + It is created in the __init__ method. + @type commands list""" + + _cache = {} + + def __init__(self, button, clicks, sleep=100000): + """Create a MouseClickType with the button, number of clicks and sleep value. + This is just a set of commands to xte that say click mouse button (specified + by button), clicks number of times, and sleep between the clicks. + @param button The mouse button number to click. + @type button int + @param clicks The number of sucessive clicks you want to do. + @type clicks int + @param sleep The amount of time to sleep inbetween the clicks. + @type sleep int""" + assert(isinstance(button, types.IntType)) + assert(isinstance(clicks, types.IntType)) + assert(isinstance(sleep, types.IntType)) + + self.commands = [] + for click in range(0, clicks): + if click != 0: + self.commands.append("usleep %d" % (sleep)) + self.commands.append("mouseclick %d" % (button)) + + @staticmethod + def _create_cached(button, clicks, sleep=100000): + """This private static method is used by the other static methods to make + sure we don't create more instances than is needed. This may not be needed, + but just seems to make sense. + @param button {@link pyrap.session.MouseClickType#__init__ See __init__} + @type button int + @param clicks {@link pyrap.session.MouseClickType#__init__ See __init__} + @type clicks int + @param sleep {@link pyrap.session.MouseClickType#__init__ See __init__} + @type sleep int + @return A cached instance of MouseClickType. + @rtype {@link pyrap.session.MouseClickType MouseClickType}""" + key = (button, clicks, sleep) + if not MouseClickType._cache.has_key(key): + MouseClickType._cache[key] = MouseClickType(button, clicks, sleep) + return MouseClickType._cache[key] + + @staticmethod + def SingleClick(): + """Create an instance of MouseClickType that represents a single click. + @return A cached instance of MouseClickType representing a Single Click. + @rtype {@link pyrap.session.MouseClickType MouseClickType}""" + return MouseClickType._create_cached(1, 1) + + @staticmethod + def DoubleClick(): + """Create an instance of MouseClickType that represents a double click. + @return A cached instance of MouseClickType representing a Double Click. + @rtype {@link pyrap.session.MouseClickType MouseClickType}""" + return MouseClickType._create_cached(1, 2) + + @staticmethod + def MiddleClick(): + """Create an instance of MouseClickType that represents a middle mouse + button click. + @return A cached instance of MouseClickType representing a middle mouse + button click. + @rtype {@link pyrap.session.MouseClickType MouseClickType}""" + return MouseClickType._create_cached(3, 1) + + @staticmethod + def RightClick(): + """Create an instance of MouseClickType that represents a right mouse + button click. + @return A cached instance of MouseClickType representing a right mouse + button click. + @rtype {@link pyrap.session.MouseClickType MouseClickType}""" + return MouseClickType._create_cached(2, 1) + + @staticmethod + def ScrollDown(clicks=3): + """Create an instance of MouseClickType that represents someone using the + wheel portion of their mouse to scroll down on a window. You can pass in + how many "clicks" or times the scroll happens, default is 3. Please note + that this doesn't mean it will scroll down 3 lines, that depends on the app, + and how it determines how many "lines" a downward scroll is. + @return A cached instance of MouseClickType representing scrolling down on + the mouse wheel. + @rtype {@link pyrap.session.MouseClickType MouseClickType}""" + return MouseClickType._create_cached(5, clicks) + + @staticmethod + def ScrollUp(clicks=3): + """Create an instance of MouseClickType that represents someone using the + wheel portion of their mouse to scroll up on a window. You can pass in + how many "clicks" or times the scroll happens, default is 3. Please note + that this doesn't mean it will scroll up 3 lines, that depends on the app, + and how it determines how many "lines" a upward scroll is. + @return A cached instance of MouseClickType representing scrolling up on the + mouse wheel. + @rtype {@link pyrap.session.MouseClickType MouseClickType}""" + return MouseClickType._create_cached(4, clicks) + + +class SpecialKeyClass: + """You shouldn't need to use this class directly. Instead an instance of this + class is provided in this module, called SpecialKeys. See the documentation + on the variable for more information. + @ivar specialKeys The master list of all special keys. This is a dict object + that maps all the normal names to internal specific + representations. Look at the source for full list if it's + not in the doc (can't seem to get epydoc to include the full + value list). + + @ivar lowerCaseNames A dict object containing the same names in it as + specialKeys, but this time all of the keys are lower cased + for case-insensitive lookup. The value portion is the real + key of specialKeys. This dict is populated on __init__.""" + specialKeys = { "Home": "Home", + "LeftArrow": "Left", + "UpArrow": "Up", + "RightArrow": "Right", + "DownArrow": "Down", + "Left": "Left", + "Up": "Up", + "Right": "Right", + "Down": "Down", + "PageUp": "Page_Up", + "PageDown": "Page_Down", + "End": "End", + "Return": "Return", + "Enter": "Return", + "Backspace": "Backspace", + "Tab": "Tab", + "Escape": "Escape", + "Delete": "Delete", + "ShiftLeft": "Shift_L", + "Shift": "Shift_L", + "ShiftRight": "Shift_R", + "ControlLeft": "Control_L", + "Control": "Control_L", + "ControlRight": "Control_R", + "WindowsLeft": "Meta_L", + "MetaLeft": "Meta_L", + "Windows": "Meta_L", + "WindowsRight": "Meta_R", + "MetaRight": "Meta_R", + "AltLeft": "Alt_L", + "Alt": "Alt_L", + "AltRight": "Alt_R"} + # Dictionary for case insensitive lookup of key names. Built in the + # constructor. + lowerCaseNames = {} + + + def __init__(self): + """Nothing special about this constructor. + <p>However, we do build the lower case names dictionary for case insensitive + lookups of key names.</p>""" + for key in self.specialKeys.keys(): + self.lowerCaseNames[key.lower()] = key + self.specialKeySet = set(self.specialKeys.values()) + + def __getattr__(self, name): + """Python calls this method when you try to access SpecialKeys.whatever. + <p>In particular you can use SpecialKeys.HOME SpecialKeys.Home or + SpecialKeys.home, they all mean the same thing. Case is in sensitive. This + method shouldn't need to be called from your code.</p>""" + if(self.specialKeys.has_key(name)): + return(self.specialKeys[name]) + elif self.lowerCaseNames.has_key(name.lower()): + return(self.specialKeys[self.lowerCaseNames[name.lower()]]) + else: + raise AttributeError, name + + def AllSpecialKeys(self): + """Get a Set of all special keys. A set is used to eliminate duplicates. + @returns A set of all special keys + @rtype set""" + return(self.specialKeySet) + + +# SpecialKeys holds name to internal mappings of the special keys you may +# need to send to your application. +SpecialKeys = SpecialKeyClass() + +class KeyCombination: + """Represents a set of keys to be pressed, ex: Ctrl-Alt-Delete. + <p>When you need to send a special key combination to the X11Session, you can + create an instance of this class to represent the key combination. """ + # Special keys for use in sending key events + ModifierKeys = frozenset([SpecialKeys.Shift, + SpecialKeys.ShiftLeft, + SpecialKeys.ShiftRight, + SpecialKeys.Control, + SpecialKeys.ControlLeft, + SpecialKeys.ControlRight, + SpecialKeys.Windows, + SpecialKeys.WindowsLeft, + SpecialKeys.WindowsRight]); + + def __init__(self, modifiers, nonmodifier): + """Create a KeyCombination by using one or more modifier keys, and one non + non-modifier. Modifiers can be a list of modifiers, or just one. You can + only have one non modifier. + @param modifiers - Either a list or a single modifier key, should come from + SpecialKeys class. + @param nonmodifier - Can be a special key that is not a modifier, or a + normal character.""" + + # First make sure that everything they passed in for modifiers are in fact + # modifiers + if not isinstance(modifiers, types.ListType): + modifiers = [modifiers,] + modifierSet = set(modifiers) + assert(modifierSet.issubset(self.ModifierKeys)) + self.commands = [] + for modifier in modifiers: + self.commands.append("keydown %s\n" % (modifier)) + + # Second make sure we only have a string representing either a SpecialKey + # or a single character + assert(isinstance(nonmodifier, types.StringTypes)) + assert(nonmodifier in SpecialKeys.AllSpecialKeys() or len(nonmodifier) == 1) + + self.commands.append("keydown %s" % (nonmodifier)) + self.commands.append("keyup %s" % (nonmodifier)) + for modifier in modifiers: + self.commands.append("keyup %s" % (modifier)) + + +class X11Exception(Exception): + """Used for problems relating to starting and running a X11 Session.""" + pass + + +class X11Session: + """X11Session is used to start a virtual X11 session, control it, and get + information from it. This is used in playback mode of pyrap. Some + functionality in this may be wrapped by other classes + @see pyrap.project.TestCase TestCase + @ivar displaynum The display number of the X server + @ivar tempdir The directory where we store the XAuthority file for the X server + @ivar xauth The full path to the XAuthority file + @ivar XServerProcess The subprocess.Popen object for the X Server + @ivar xteProcess The subprocess.Popen object for the xte program""" + + def __init__(self, width, height, depth=16): + """Start a virtual X session (using Xvfb). The virtual X server is started, + and the subprocess.Popen object is saved. Also started is xte, the process + that is used to send mouse and keyboard events to the X server. The startup + process is as follows: + <ol> + <li>Create a temporary directory</li> + <li>Use mcookie to get a hex key for XAuth file</li> + <li>Find open display</li> + <li>Start Xvfb</li> + <li>Start xte</li> + </ol> + @param width The width of the X screen + @param height The height of the X screen + @param depth The color depth of the X screen (default 16bpp) + @type width int + @type height int + @type depth int""" + assert(isinstance(width, types.IntType)) + assert(isinstance(height, types.IntType)) + assert(isinstance(depth, types.IntType)) + self.width = width + self.height = height + self.tempdir = tempfile.mkdtemp("pyrap") + self.xauth = self.tempdir + "/Xauthority" + mcookieproc = subprocess.Popen(args=["mcookie"], stdout=subprocess.PIPE) + retval = mcookieproc.wait() + if retval != 0: + raise X11Exception, "Return value from mcookie was %d." % (retval) + mcookie = mcookieproc.stdout.readline() + + self.displaynum = self._findOpenDisplay() + self.newenviron = dict(os.environ) + self.newenviron['XAUTHORITY'] = self.xauth + self.newenviron['DISPLAY'] = ":%d" % (self.displaynum) + retval = subprocess.call(args=["xauth", "add", self.newenviron['DISPLAY'], ".", mcookie], env=self.newenviron) + if retval != 0: + raise X11Exception, "Return value from mcookie was %d." % (retval) + if os.environ.has_key("XAUTHORITY"): + subprocess.call(args=["xauth", "merge", self.newenviron['XAUTHORITY']]) + + self.XServerProcess = subprocess.Popen(args=["Xvfb", self.newenviron['DISPLAY'], "-screen", "0", "%dx%dx%d" % (width, height, depth)], env=self.newenviron) + self.xteProcess = subprocess.Popen(args=["xte"], env=self.newenviron, stdin=subprocess.PIPE) + self.display = gtk.gdk.Display(self.newenviron['DISPLAY']) + self.default_colormap = self.display.get_default_screen().get_default_colormap() + self.root_window = self.display.get_default_screen().get_root_window() + + atexit.register(self._cleanup) + + def sendString(self, chars): + """Send a string to the X11Session. This is done through the use of xte. + @param chars The string of characters you want to send to the X server + @type chars str""" + assert(isinstance(chars, types.StringTypes)) + self.xteProcess.stdin.write("str %s\n" % (chars)) + + def sendKeyCombination(self, combo): + """Send a key combination, like ctrl-alt-delete, to the X server. + @param combo KeyCombination to send to the X server + @type combo pyrap.session.KeyCombination""" + assert(isinstance(combo, KeyCombination)) + for command in combo.commands: + self.xteProcess.stdin.write(command) + + def pushKey(self, key): + """Send a push and release key event to the X Session. + @param key Can be a single character, or a SpecialKey. + @type key str""" + assert(isinstance(key, types.StringTypes)) + assert(len(key) == 1 or set([key]).issubset(SpecialKeys.specialKeySet)) + self.xteProcess.stdin.write("key %s\n" % (key)) + + def moveMouseTo(self, x, y): + """Move the mouse pointer to the specified coordinates. + @param x the x coordinate to move to, 0 is at the left of the screen + @param y the y coordinate to move to, 0 is at the top of the screen + @type x int + @type y int""" + assert(isinstance(x, types.IntType)) + assert(isinstance(x, types.IntType)) + self.xteProcess.stdin.write("mousemove %d %d\n" % (x, y)) + + def clickMouse(self, mouseclick): + """Click the mouse button. Nothing special, but it does the job. + @param mouseclick An object describing the mouse click and the number of + of times to click it. + @type mouseclick {@link pyrap.session.MouseClickType MouseClickType}""" + assert(isinstance(mouseclick, MouseClickType)) + for xte_command in mouseclick.commands: + self.xteProcess.stdin.write("%s\n" % (xte_command)) + + + def _findOpenDisplay(self, display=50): + """Look for an open X11 Display. This method checks /tmp/.X[display]-lock, + starting at 50. + @param display The display number to start checking for. + @type display int + @returns Open Display Number + @rtype int""" + while os.access("/tmp/.X%d-lock" % (display), os.F_OK): + display += 1 + return display + + def getScreenShot(self): + """Get a screen shot of the X11 Screen. This is needed for several reasons, + most for internal use. The imagerec module needs screen shots to locate + images on the screen. The record application needs constant screen shots to + display what's going on so that the user can make the right actions for + recording. + @return Screen shot of the X11 Session + @rtype gtk.gdk.Pixbuf""" + sspb = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, False, 8, self.width, self.height) + sspb.get_from_drawable(self.root_window, self.default_colormap, 0, 0, 0, 0, self.width, self.height) + return sspb + + + def _cleanup(self): + """Registered in __init__ as a shutdown hook. X11Session needs to clean up + several things. At this point a lot of processes running, and temp files + have been created.""" + if os.environ.has_key("XAUTHORITY"): + subprocess.call(args=["xauth", "remove", self.newenviron['DISPLAY']]) + if self.xteProcess.poll() is None: + self.xteProcess.stdin.close() + if self.xteProcess.poll() is None: + os.kill(self.xteProcess.pid, signal.SIGTERM) + if self.XServerProcess.poll() is None: + os.kill(self.XServerProcess.pid, signal.SIGTERM) + os.unlink(self.xauth) + os.rmdir(self.tempdir) + Property changes on: pyrap/pyrap/session.py ___________________________________________________________________ Name: svn:executable + * Name: svn:mime-type + text/plain Name: svn:eol-style + native This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jco...@us...> - 2006-02-24 23:11:16
|
Revision: 1 Author: jcorbett Date: 2006-02-24 15:11:06 -0800 (Fri, 24 Feb 2006) ViewCVS: http://svn.sourceforge.net/pyrap/?rev=1&view=rev Log Message: ----------- Initial import into subversion Added Paths: ----------- pyrap/ pyrap/LICENSE.txt pyrap/doc/ pyrap/doc/html/ pyrap/doc/pdf/ pyrap/gendoc.sh pyrap/pyrap/ pyrap/pyrap/logging-defaults.ini pyrap/pyrap/project-defaults.ini pyrap/pyrap.wpr pyrap/pyrap.wpu Added: pyrap/LICENSE.txt =================================================================== --- pyrap/LICENSE.txt (rev 0) +++ pyrap/LICENSE.txt 2006-02-24 23:11:06 UTC (rev 1) @@ -0,0 +1,18 @@ +Copyright (c) 2005 Jason Corbett + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Property changes on: pyrap/LICENSE.txt ___________________________________________________________________ Name: svn:mime-type + text/plain Name: svn:eol-style + native Added: pyrap/gendoc.sh =================================================================== --- pyrap/gendoc.sh (rev 0) +++ pyrap/gendoc.sh 2006-02-24 23:11:06 UTC (rev 1) @@ -0,0 +1,4 @@ +#!/bin/bash + +epydoc --html -o doc/html -n Pyrap -u 'http://pyrap.sourceforge.net' -c white --private pyrap +epydoc --pdf -o doc/pdf -n Pyrap -u 'http://pyrap.sourceforge.net' -c white --private pyrap Property changes on: pyrap/gendoc.sh ___________________________________________________________________ Name: svn:executable + Name: svn:mime-type + text/plain Name: svn:eol-style + native Added: pyrap/pyrap/logging-defaults.ini =================================================================== --- pyrap/pyrap/logging-defaults.ini (rev 0) +++ pyrap/pyrap/logging-defaults.ini 2006-02-24 23:11:06 UTC (rev 1) @@ -0,0 +1,42 @@ +[loggers] +keys=root,pyrap,testcase + +[handlers] +keys=root,pyrap,testcase + +[formatters] +keys=all + +[logger_pyrap] +qualname=pyrap +level=WARNING +handlers=pyrap + +[logger_testcase] +level=INFO +qualname=testcase +handlers=testcase + +[logger_root] +level=NOTSET +handlers=root + +[handler_root] +class=StreamHandler +level=CRITICAL +formatter=all +args=(sys.stderr,) + +[handler_pyrap] +class=FileHandler +formatter=all +args=('%(tcroot)s/logs/pyrap.log', 'w') + +[handler_testcase] +class=FileHandler +formatter=all +args=('%(tcroot)s/logs/testcase.log', 'w') + +[formatter_all] +format=%(asctime)s,%(levelname)8s,%(name)s,%(message)s +datefmt= Property changes on: pyrap/pyrap/logging-defaults.ini ___________________________________________________________________ Name: svn:mime-type + text/plain Name: svn:eol-style + native Added: pyrap/pyrap/project-defaults.ini =================================================================== --- pyrap/pyrap/project-defaults.ini (rev 0) +++ pyrap/pyrap/project-defaults.ini 2006-02-24 23:11:06 UTC (rev 1) @@ -0,0 +1,10 @@ +[Test Case] +name = Default Test Case Name +logging = normal +logging.configfile = logging.ini + +[X11 Session] +resolution.x = 1024 +resolution.y = 768 +color depth = 16 + Property changes on: pyrap/pyrap/project-defaults.ini ___________________________________________________________________ Name: svn:mime-type + text/plain Name: svn:eol-style + native Added: pyrap/pyrap.wpr =================================================================== --- pyrap/pyrap.wpr (rev 0) +++ pyrap/pyrap.wpr 2006-02-24 23:11:06 UTC (rev 1) @@ -0,0 +1,93 @@ +#!wing +#!version=2.0 +################################################################## +# Wing IDE project file # +################################################################## +[project attributes] +proj.file-list = [loc('.cvsignore'), + loc('.project'), + loc('LICENSE'), + loc('doc/html/.cvsignore'), + loc('doc/html/epydoc.css'), + loc('doc/html/index.html'), + loc('doc/html/private/UserDict.UserDict-class.html'), + loc('doc/html/private/epydoc.css'), + loc('doc/html/private/exceptions.Exception-class.html'), + loc('doc/html/private/frames.html'), + loc('doc/html/private/help.html'), + loc('doc/html/private/index.html'), + loc('doc/html/private/indices.html'), + loc('doc/html/private/pyrap-module.html'), + loc('doc/html/private/pyrap.imagerec-module.html'), + loc('doc/html/private/pyrap.imagerec.ImageRecognitionException-class.html'), + loc('doc/html/private/pyrap.imagerec.SearchPattern-class.html'), + loc('doc/html/private/pyrap.project-module.html'), + loc('doc/html/private/pyrap.project.TestCase-class.html'), + loc('doc/html/private/pyrap.session-module.html'), + loc('doc/html/private/pyrap.session.KeyCombination-class.html'), + loc('doc/html/private/pyrap.session.SpecialKeyClass-class.html'), + loc('doc/html/private/pyrap.session.X11Exception-class.html'), + loc('doc/html/private/pyrap.session.X11Session-class.html'), + loc('doc/html/private/toc-everything.html'), + loc('doc/html/private/toc-pyrap-module.html'), + loc('doc/html/private/toc-pyrap.imagerec-module.html'), + loc('doc/html/private/toc-pyrap.project-module.html'), + loc('doc/html/private/toc-pyrap.session-module.html'), + loc('doc/html/private/toc.html'), + loc('doc/html/private/trees.html'), + loc('doc/html/public/UserDict.UserDict-class.html'), + loc('doc/html/public/epydoc.css'), + loc('doc/html/public/exceptions.Exception-class.html'), + loc('doc/html/public/frames.html'), + loc('doc/html/public/help.html'), + loc('doc/html/public/index.html'), + loc('doc/html/public/indices.html'), + loc('doc/html/public/pyrap-module.html'), + loc('doc/html/public/pyrap.imagerec-module.html'), + loc('doc/html/public/pyrap.imagerec.ImageRecognitionException-class.html'), + loc('doc/html/public/pyrap.imagerec.SearchPattern-class.html'), + loc('doc/html/public/pyrap.project-module.html'), + loc('doc/html/public/pyrap.project.TestCase-class.html'), + loc('doc/html/public/pyrap.session-module.html'), + loc('doc/html/public/pyrap.session.KeyCombination-class.html'), + loc('doc/html/public/pyrap.session.SpecialKeyClass-class.html'), + loc('doc/html/public/pyrap.session.X11Exception-class.html'), + loc('doc/html/public/pyrap.session.X11Session-class.html'), + loc('doc/html/public/toc-everything.html'), + loc('doc/html/public/toc-pyrap-module.html'), + loc('doc/html/public/toc-pyrap.imagerec-module.html'), + loc('doc/html/public/toc-pyrap.project-module.html'), + loc('doc/html/public/toc-pyrap.session-module.html'), + loc('doc/html/public/toc.html'), + loc('doc/html/public/trees.html'), + loc('doc/pdf/.cvsignore'), + loc('doc/pdf/api.aux'), + loc('doc/pdf/api.dvi'), + loc('doc/pdf/api.idx'), + loc('doc/pdf/api.ilg'), + loc('doc/pdf/api.ind'), + loc('doc/pdf/api.log'), + loc('doc/pdf/api.out'), + loc('doc/pdf/api.pdf'), + loc('doc/pdf/api.ps'), + loc('doc/pdf/api.tex'), + loc('doc/pdf/api.toc'), + loc('doc/pdf/pyrap-module.aux'), + loc('doc/pdf/pyrap-module.tex'), + loc('doc/pdf/pyrap.imagerec-module.aux'), + loc('doc/pdf/pyrap.imagerec-module.tex'), + loc('doc/pdf/pyrap.project-module.aux'), + loc('doc/pdf/pyrap.project-module.tex'), + loc('doc/pdf/pyrap.session-module.aux'), + loc('doc/pdf/pyrap.session-module.tex'), + loc('gendoc.sh'), + loc('pyrap.wpr'), + loc('pyrap.wpu'), + loc('pyrap/.cvsignore'), + loc('pyrap/__init__.py'), + loc('pyrap/imagerec.py'), + loc('pyrap/logging-defaults.ini'), + loc('pyrap/project-defaults.ini'), + loc('pyrap/project.py'), + loc('pyrap/session.py')] +proj.file-type = 'shared' Property changes on: pyrap/pyrap.wpr ___________________________________________________________________ Name: svn:mime-type + text/plain Name: svn:eol-style + native Added: pyrap/pyrap.wpu =================================================================== --- pyrap/pyrap.wpu (rev 0) +++ pyrap/pyrap.wpu 2006-02-24 23:11:06 UTC (rev 1) @@ -0,0 +1,308 @@ +#!wing +#!version=2.0 +################################################################## +# Wing IDE project file : User-specific branch # +################################################################## +[user attributes] +debug.shell-history = {None: ['blah = "hello"\n', + 'blah\n', + 'len(blah)\n', + 'type(blah)\n', + 'import types\n', + 'types.StringType\n']} +guimgr.overall-gui-state = {'windowing-policy': 'combined-window', + 'windows': [{'name': 'TFpQN7bPQCYzusFVdQfDDKcMxA'\ + '76l3h4', + 'size-state': '', + 'type': 'dock', + 'view': {'area': 'tall', + 'current_pages': [0, + 1], + 'notebook_display': 'normal', + 'notebook_percent': 0.25, + 'override_title': None, + 'pagelist': [('indent', + 'tall', + 2, + {}), + ('project', + 'tall', + 0, + {'tree-state': {'tree-states': {'deep': {'col'\ + 'umn-widths': [1.0], + 'expanded-nodes': [(1,)], + 'selected-nodes': [(1, + 3)], + 'top-node': (0,)}}, + 'tree-style': 'deep'}}), + ('source-assistant', + 'tall', + 2, + {'docstring-during-complete': 0, + 'wrap-lines': True}), + ('browser', + 'tall', + 0, + {'all_tree_states': {loc('pyrap/__init__.py'): {''\ + 'column-widths': [1.0], + 'expanded-nodes': [], + 'selected-nodes': [], + 'top-node': [('generic attribute', + loc('pyrap/__init__.py'), + '__all__')]}, + loc('pyrap/imagerec.py'): {'column-widths': [1.0], + 'expanded-nodes': [], + 'selected-nodes': [[('class def', + loc('pyrap/imagerec.py'), + 'SearchPattern')]], + 'top-node': [('class def', + loc('pyrap/imagerec.py'), + 'ImageRecognitionException')]}, + loc('pyrap/logging-defaults.ini'): {'column-widths': [1.0], + 'expanded-nodes': [], + 'selected-nodes': [], + 'top-node': None}, + loc('pyrap/project-defaults.ini'): {'column-widths': [1.0], + 'expanded-nodes': [], + 'selected-nodes': [], + 'top-node': None}, + loc('pyrap/project.py'): {'column-widths': [1.0], + 'expanded-nodes': [], + 'selected-nodes': [[('class def', + loc('pyrap/project.py'), + 'TestCase')]], + 'top-node': [('class def', + loc('pyrap/project.py'), + 'TestCase')]}, + loc('pyrap/session.py'): {'column-widths': [1.0], + 'expanded-nodes': [[('class def', + loc('pyrap/session.py'), + 'X11Session')]], + 'selected-nodes': [[('class def', + loc('pyrap/session.py'), + 'X11Session')]], + 'top-node': [('class def', + loc('pyrap/session.py'), + 'KeyCombination')]}}, + 'browse_mode': u'Current Module', + 'follow-selection': True, + 'sort_mode': 'Alphabetically', + 'visibility_options': {u'Derived Classes': False, + u'Imported': False, + u'Modules': True}})], + 'primary_view_state': {'area': 'wide', + 'current_pages': [1, + 3], + 'notebook_display': 'normal', + 'notebook_percent': 0.30000000000000004, + 'override_title': None, + 'pagelist': [('debug-io', + 'wide', + 1, + None), + ('debug-probe', + 'wide', + 2, + None), + ('debug-exceptions', + 'wide', + 0, + {}), + ('debug-modules', + 'wide', + 1, + None), + ('python-shell', + 'wide', + 2, + {'first-line': 0, + 'selection_end': 155, + 'selection_start': 155}), + ('search', + 'wide', + 0, + {'action': 'search', + 'file-set': None, + 'mode': 'file', + 'options': {'AutoBackground': 1, + 'AutoFind': 1, + 'AutoShowBatch': 0, + 'Fast': 1, + 'Incremental': 1, + 'InterpretBackslash': 0, + 'MatchCase': 0, + 'OmitBinary': 1, + 'Recursive': 1, + 'ReplaceOnDisk': 0, + 'Reverse': 0, + 'WholeWords': 0, + 'Wrapping': 1}, + 'prefix-file': 'short-file', + 'prefix-lineno': 1, + 'regex-flags': 46, + 'replace-entry-expanded': False, + 'replace-string': '', + 'scope': ['current-file-batch'], + 'search-entry-expanded': False, + 'search-string': '"test case"', + 'search-style': 'text', + 'starting-directory': '/home/jasonc/'}), + ('debug-data', + 'wide', + 0, + {}), + ('debug-watch', + 'wide', + 1, + None)], + 'primary_view_state': {'editor_states': {'bookmarks': ([(loc('pyrap/project.py'), + {'first-line': 25, + 'selection_end': 2074, + 'selection_start': 2074}, + 1115925731.466718), + (loc('pyrap/project.py'), + {'first-line': 25, + 'selection_end': 2417, + 'selection_start': 2417}, + 1115925740.2269599), + (loc('pyrap/project.py'), + {'first-line': 25, + 'selection_end': 2421, + 'selection_start': 2413}, + 1115925750.93712), + (loc('pyrap/project.py'), + {'first-line': 40, + 'selection_end': 2746, + 'selection_start': 2738}, + 1115925752.2315431), + (loc('pyrap/project.py'), + {'first-line': 40, + 'selection_end': 2525, + 'selection_start': 2525}, + 1115925753.2634411), + (loc('pyrap/project.py'), + {'first-line': 40, + 'selection_end': 2744, + 'selection_start': 2744}, + 1115925758.670579), + (loc('pyrap/project.py'), + {'first-line': 40, + 'selection_end': 2866, + 'selection_start': 2858}, + 1115925766.3009319), + (loc('pyrap/project.py'), + {'first-line': 51, + 'selection_end': 2972, + 'selection_start': 2964}, + 1115925767.2537341), + (loc('pyrap/project.py'), + {'first-line': 70, + 'selection_end': 4691, + 'selection_start': 4683}, + 1115925769.7895639), + (loc('pyrap/project.py'), + {'first-line': 78, + 'selection_end': 5156, + 'selection_start': 5148}, + 1115925772.670465), + (loc('pyrap/project.py'), + {'first-line': 78, + 'selection_end': 4945, + 'selection_start': 4937}, + 1115925774.077225), + (loc('pyrap/project.py'), + {'first-line': 0, + 'selection_end': 8266, + 'selection_start': 8258}, + 1115925778.7571599), + (loc('pyrap/project.py'), + {'first-line': 15, + 'selection_end': 2019, + 'selection_start': 2019}, + 1115925860.205672), + (loc('pyrap/project.py'), + {'first-line': 15, + 'selection_end': 2023, + 'selection_start': 2012}, + 1115925868.6536751), + (loc('pyrap/project.py'), + {'first-line': 27, + 'selection_end': 2075, + 'selection_start': 2075}, + 1115925869.861798), + (loc('pyrap/project.py'), + {'first-line': 27, + 'selection_end': 2526, + 'selection_start': 2526}, + 1115925876.9711919), + (loc('pyrap/project.py'), + {'first-line': 31, + 'selection_end': 2400, + 'selection_start': 2400}, + 1115925884.8012631), + (loc('pyrap/logging-defaults.ini'), + {'first-line': 0, + 'selection_end': 0, + 'selection_start': 0}, + 1115929869.7150259), + (loc('pyrap/project-defaults.ini'), + {'first-line': 0, + 'selection_end': 0, + 'selection_start': 0}, + 1115932586.8843019), + [loc('pyrap/project.py'), + {'first-line': 31, + 'selection_end': 2400, + 'selection_start': 2400}, + 1115932591.475754]], + 19), + 'current-loc': loc('pyrap/project.py'), + 'editor-states': {loc('pyrap/__init__.py'): {'first-line': 0, + 'selection_end': 0, + 'selection_start': 0}, + loc('pyrap/imagerec.py'): {'first-line': 92, + 'selection_end': 2776, + 'selection_start': 2776}, + loc('pyrap/logging-defaults.ini'): {'first-line': 0, + 'selection_end': 0, + 'selection_start': 0}, + loc('pyrap/project-defaults.ini'): {'first-line': 0, + 'selection_end': 0, + 'selection_start': 0}, + loc('pyrap/project.py'): {'first-line': 32, + 'selection_end': 2492, + 'selection_start': 2492}, + loc('pyrap/session.py'): {'first-line': 211, + 'selection_end': 7680, + 'selection_start': 7670}}, + 'has-focus': True}, + 'open_files': [u'pyrap/__init__.py', + u'pyrap/imagerec.py', + u'pyrap/session.py', + u'pyrap/logging-defaults.ini', + u'pyrap/project-defaults.ini', + u'pyrap/project.py']}, + 'split_percents': {0: 0.5}, + 'splits': 2, + 'tab_location': 'top', + 'user_data': {}}, + 'split_percents': {0: 0.5}, + 'splits': 2, + 'tab_location': 'right', + 'user_data': {}}, + 'window-alloc': (0, + 27, + 1580, + 1093)}]} +guimgr.recent-documents = [loc('pyrap/project.py'), + loc('pyrap/project-defaults.ini'), + loc('pyrap/logging-defaults.ini'), + loc('pyrap/session.py')] +proj.env-vars = {None: ('default', + [''])} +proj.revision-control = True +search.search-history = ['"test case"', + '"test case', + 'test case', + 'test ', + 'testcase'] Property changes on: pyrap/pyrap.wpu ___________________________________________________________________ Name: svn:mime-type + text/plain Name: svn:eol-style + native This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: Jason C. <jas...@gm...> - 2006-02-24 22:01:53
|
is this list alive? |
From: Jason C. <jas...@gm...> - 2005-05-18 19:57:04
|
I'm working on finishing up a release this week. It will only have the=20 playback api finished, although I will have example test cases. Record app= =20 uses the playback api, so I had to finish this first. Jason Corbett |
From: Jason C. <jco...@vi...> - 2005-04-20 17:12:15
|
another try |
From: Jason C. <jco...@vi...> - 2005-04-20 16:52:07
|
since this message only goes to me right now, no one should care :) Jason Corbett |