diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..2888e8e --- /dev/null +++ b/.editorconfig @@ -0,0 +1,24 @@ +# EditorConfig is awesome: http://EditorConfig.org + +# top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file +[*] +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 4 + +[{*.yml,*.yaml}] +indent_style = space +indent_size = 2 + +[*.py] +indent_style = space +indent_size = 2 + +# Tab indentation (no size specified) +[Makefile*] +indent_style = tab + diff --git a/ldtp/__init__.py b/ldtp/__init__.py index 48a32fc..0cc2171 100644 --- a/ldtp/__init__.py +++ b/ldtp/__init__.py @@ -39,9 +39,9 @@ path = "." sys.path.append(path) -import state -import client -from client_exception import LdtpExecutionError +from . import state +from . import client +from .client_exception import LdtpExecutionError _t = None _pollEvents = None @@ -320,6 +320,7 @@ def poll_server(self): # self._callback[name][0] - Event type # self._callback[name][1] - Callback function # self._callback[name][2] - Arguments to callback function + print(str(event.source) + " " + str(event.type)) for name in self._callback: # Window created event # User registered window events @@ -397,7 +398,7 @@ def imagecapture(window_name = None, out_file = None, x = 0, y = 0, try: f.write(b64decode(data)) # Python 2 except TypeError: - f.write(b64decode(bytes(data,'utf-8'))) # Python 3 + f.write(b64decode(data.data)) # Python 3 f.close() return out_file @@ -414,8 +415,8 @@ def waittillguinotexist(window_name, object_name = '', guiTimeOut) def guiexist(window_name, object_name = ''): return _remote_guiexist(window_name, object_name) -def launchapp(cmd, args = [], delay = 0, env = 1, lang = "C"): - return _remote_launchapp(cmd, args, delay, env, lang) +def launchapp(cmd, args = [], delay = 0, env = 1, lang = "C", logfiles = None ): + return _remote_launchapp(cmd, args, delay, env, lang, logfiles) def hasstate(window_name, object_name, state, guiTimeOut = 0): return _remote_hasstate(window_name, object_name, state, guiTimeOut) def selectrow(window_name, object_name, row_text): @@ -445,7 +446,7 @@ def deletetext(window_name, object_name, start, end = -1): def startprocessmonitor(process_name, interval = 2): return _remote_startprocessmonitor(process_name, interval) def gettextvalue(window_name, object_name, startPosition = 0, endPosition = 0): - return unicode(_remote_gettextvalue(window_name, object_name, startPosition, endPosition)) + return str(_remote_gettextvalue(window_name, object_name, startPosition, endPosition)) def getcellvalue(window_name, object_name, row_index, column = 0): return _remote_getcellvalue(window_name, object_name, row_index, column) def getcellsize(window_name, object_name, row_index, column = 0): diff --git a/ldtp/client.py b/ldtp/client.py index 8fed1d1..66ae690 100644 --- a/ldtp/client.py +++ b/ldtp/client.py @@ -28,8 +28,8 @@ import traceback import subprocess from socket import error as SocketError -from ldtp.log import logger -from ldtp.client_exception import LdtpExecutionError, ERROR_CODE +from .log import logger +from .client_exception import LdtpExecutionError, ERROR_CODE try: import xmlrpclib @@ -70,8 +70,12 @@ class _Method(xmlrpclib._Method): def __call__(self, *args, **kwargs): if _ldtp_debug: logger.debug('%s(%s)' % (self.__name, \ - ', '.join(map(repr, args) + ['%s=%s' % (k, repr(v)) \ + ', '.join(list(map(repr, args)) + ['%s=%s' % (k, repr(v)) \ for k, v in kwargs.items()]))) + try: + return self.__send(self.__name, args) + except BaseException as be: + logger.debug('%s(%s) Trying once more' % (self.__name, str(be))) return self.__send(self.__name, args) class Transport(xmlrpclib.Transport): diff --git a/ldtpd/__init__.py b/ldtpd/__init__.py index 9f601bb..df72b01 100644 --- a/ldtpd/__init__.py +++ b/ldtpd/__init__.py @@ -35,7 +35,7 @@ def send(self): os.kill(int(self.parentpid), signal.SIGUSR1) -from xmlrpc_daemon import XMLRPCLdtpd +from .xmlrpc_daemon import XMLRPCLdtpd def main(port=4118, parentpid=None, XMLRPCLdtpdFactory=lambda: XMLRPCLdtpd()): import os os.environ['NO_GAIL'] = '1' diff --git a/ldtpd/combo_box.py b/ldtpd/combo_box.py index ca4dc68..a309c9c 100644 --- a/ldtpd/combo_box.py +++ b/ldtpd/combo_box.py @@ -20,8 +20,8 @@ """ import pyatspi -from utils import Utils -from server_exception import LdtpServerException +from .utils import Utils +from .server_exception import LdtpServerException class LayeredPane(Utils): def _lp_selectitem(self, obj, item_name): @@ -283,7 +283,7 @@ def unselectall(self, window_name, object_name): except: raise LdtpServerException('Unable to select all item') -class ComboBox(Utils, LayeredPane): +class ComboBox(LayeredPane): def selectitem(self, window_name, object_name, item_name): """ Select combo box / layered pane item diff --git a/ldtpd/core.py b/ldtpd/core.py index 161230a..67ad5e5 100644 --- a/ldtpd/core.py +++ b/ldtpd/core.py @@ -26,6 +26,8 @@ import subprocess try: # If we have gtk3+ gobject introspection, use that + import gi + gi.require_version('Wnck', '3.0') from gi.repository import Wnck as wnck from gi.repository import Gtk as gtk from gi.repository import Gdk as gdk @@ -40,14 +42,14 @@ # Not all environments support wnck package pass gtk3=False -from utils import Utils, ProcessStats -from constants import abbreviated_roles -from keypress_actions import KeyboardOp -from waiters import ObjectExistsWaiter, GuiExistsWaiter, \ +from .utils import Utils, ProcessStats +from .constants import abbreviated_roles +from .keypress_actions import KeyboardOp +from .waiters import ObjectExistsWaiter, GuiExistsWaiter, \ GuiNotExistsWaiter, ObjectNotExistsWaiter, NullWaiter, \ MaximizeWindow, MinimizeWindow, UnmaximizeWindow, UnminimizeWindow, \ ActivateWindow, CloseWindow -from server_exception import LdtpServerException +from .server_exception import LdtpServerException import os import re import sys @@ -56,19 +58,19 @@ import traceback from fnmatch import translate as glob_trans -from menu import Menu -from text import Text -from mouse import Mouse -from table import Table -from value import Value -from generic import Generic -from combo_box import ComboBox -from page_tab_list import PageTabList +from .menu import Menu +from .text import Text +from .mouse import Mouse +from .table import Table +from .value import Value +from .generic import Generic +from .combo_box import ComboBox +from .page_tab_list import PageTabList from gi.repository import GLib -import thread +import _thread -class Ldtpd(Utils, ComboBox, Table, Menu, PageTabList, +class Ldtpd(ComboBox, Table, Menu, PageTabList, Text, Mouse, Generic, Value): """ Core LDTP class. @@ -101,6 +103,15 @@ def __del__(self): self._process_stats[key].stop() def _registered_event_cb(self, event): + l = [ "object:text-changed", "object:bounds-changed"] + show = True + for x in l: + if str(event.type).startswith(x): + show = False + if show: + print("event: " + str(event.source) + " " + str(event.type)) + #import pdb + #pdb.set_trace() try: if event and event.source and event.type: abbrev_role, abbrev_name, label_by=self._ldtpize_accessible( \ @@ -132,6 +143,9 @@ def _registered_kb_event_cb(self, event): def _event_cb(self, event): try: + if event: + print(dir(event)) + print(event) if event and event.type == "window:create" and event.source: for window in self._callback: if window and self._match_name_to_acc(window, event.source): @@ -183,7 +197,7 @@ def getapplist(self): # A11Y lookup error continue except GLib.Error as ge: - if "The application no longer exists" in ge: + if "The application no longer exists" in repr(ge): continue raise return app_list @@ -247,7 +261,16 @@ def delaycmdexec(self, delay=None): """ self._delaycmdexec=delay - def launchapp(self, cmd, args=[], delay=0, env=1, lang="C"): + def _cleanupProcess(self, process, logfile_fds): + """ Helper function to wait until the process has finished and then clean it up + """ + process.wait() + if logfile_fds: + for f in logfile_fds: + if f: + f.close() + + def launchapp(self, cmd, args=[], delay=0, env=1, lang="C", logfiles=None): """ Launch application. @@ -261,6 +284,8 @@ def launchapp(self, cmd, args=[], delay=0, env=1, lang="C"): @type env: int @param lang: Application language to be used @type lang: string + @param logfiles: Optional filename-tuple to capture standard output and standard error. Output will be appended. + @type logfiles: (string, string) @return: PID of new process @rtype: integer @@ -276,13 +301,18 @@ def launchapp(self, cmd, args=[], delay=0, env=1, lang="C"): if lang: os.environ['LANG']=lang try: - process=subprocess.Popen([cmd]+args, close_fds=True) + files = None + if logfiles is None: + process=subprocess.Popen([cmd]+args, close_fds=True) + else: + files = [open(f, "a") if f else None for f in logfiles] + process=subprocess.Popen([cmd]+args, stdout=files[0], stderr=files[1]) # Let us wait so that the application launches try: time.sleep(int(delay)) except ValueError: time.sleep(5) - thread.start_new_thread(process.wait,()) + _thread.start_new_thread(self._cleanupProcess,(process, files)) except Exception as e: raise LdtpServerException(str(e)) os.environ['NO_GAIL']='1' @@ -456,7 +486,7 @@ def removecallback(self, window_name): return 1 - def registerevent(self, event_name): + def registerevent(self, event_name, cb=None): """ Register at-spi event @@ -466,11 +496,13 @@ def registerevent(self, event_name): @return: 1 if registration was successful, 0 if not. @rtype: integer """ + if cb is None: + cb = self._registered_event_cb pyatspi.Registry.deregisterEventListener( \ - self._registered_event_cb, *self._registered_events) + cb, *self._registered_events) self._registered_events.append(event_name) - pyatspi.Registry.registerEventListener(self._registered_event_cb, + pyatspi.Registry.registerEventListener(cb, *self._registered_events) return 1 @@ -1574,7 +1606,7 @@ def getaccesskey(self, window_name, object_name): key_binding = '' try: iaction = obj.queryAction() - for j in xrange(iaction.nActions): + for j in range(iaction.nActions): if iaction.getKeyBinding(j) != '': key_binding = iaction.getKeyBinding(j) break diff --git a/ldtpd/generic.py b/ldtpd/generic.py index 3c8f265..02c9ba8 100644 --- a/ldtpd/generic.py +++ b/ldtpd/generic.py @@ -33,8 +33,8 @@ import tempfile from base64 import b64encode -from utils import Utils -from server_exception import LdtpServerException +from .utils import Utils +from .server_exception import LdtpServerException class Generic(Utils): def imagecapture(self, window_name = None, x = 0, y = 0, @@ -193,7 +193,7 @@ def imagecapture(self, window_name = None, x = 0, y = 0, pb.save(tmpFile, 'png') del pb gc.collect() - rv = b64encode(open(tmpFile).read()) + rv = b64encode(open(tmpFile,'rb').read()) os.remove(tmpFile) return rv diff --git a/ldtpd/keypress_actions.py b/ldtpd/keypress_actions.py index 4d36db3..2c46c8b 100644 --- a/ldtpd/keypress_actions.py +++ b/ldtpd/keypress_actions.py @@ -21,6 +21,7 @@ import re import time + try: from gi.repository import GObject as gobject except: @@ -28,7 +29,7 @@ import pyatspi import subprocess -from sequence_step import AtomicAction +from .sequence_step import AtomicAction _ = lambda x: x # Highest granularity, define timing for every single press and release @@ -62,7 +63,7 @@ def _get_keyboard_keycodes(): shell = True, close_fds = True).communicate() if output[0] != '': output = output[0] - for line in output.split('\n'): + for line in output.decode().split('\n'): if line.strip() == '': continue split = re.split('=', line, maxsplit = 2) diff --git a/ldtpd/menu.py b/ldtpd/menu.py index 25a9673..d0e1aa4 100644 --- a/ldtpd/menu.py +++ b/ldtpd/menu.py @@ -21,7 +21,7 @@ import re import pyatspi -from utils import Utils +from .utils import Utils class Menu(Utils): def selectmenuitem(self, window_name, object_name): diff --git a/ldtpd/mouse.py b/ldtpd/mouse.py index bf45822..1ecd106 100644 --- a/ldtpd/mouse.py +++ b/ldtpd/mouse.py @@ -21,8 +21,8 @@ import time import pyatspi -from utils import Utils -from server_exception import LdtpServerException +from .utils import Utils +from .server_exception import LdtpServerException class Mouse(Utils): """ @@ -159,41 +159,17 @@ def simulatemousemove(self, source_x, source_y, dest_x, dest_y, delay = 0.0): dest_x < size[0] or dest_y < size[1]): return 0 - x_flag = False # Iterated x ? - y_flag = False # Iterated y ? + # int() to assure being a natural number + steps = int(max(abs(source_x-dest_x), abs(source_y-dest_y))) + step = 0 while True: - if not x_flag: - if source_x > dest_x: - # If source X greather than dest X - # then move -1 pixel - source_x -= 1 - elif source_x < dest_x: - # If source X less than dest X - # then move +1 pixel - source_x += 1 - else: - # If source X equal to dest X - # then don't process X co-ordinate - x_flag = True - if not y_flag: - if source_y > dest_y: - # If source Y greather than dest Y - # then move -1 pixel - source_y -= 1 - elif source_y < dest_y: - # If source Y less than dest Y - # then move +1 pixel - source_y += 1 - else: - # If source Y equal to dest Y - # then don't process Y co-ordinate - y_flag = True + current_x = int(source_x + ((dest_x-source_x) * step) / steps) + current_y = int(source_y + ((dest_y-source_y) * step) / steps) + step = step + 1 if delay: time.sleep(delay) # Start mouse move from source_x, source_y to dest_x, dest_y - self.generatemouseevent(source_x, source_y, 'abs') - if source_x == dest_x and source_y == dest_y: - # If we have reached the dest_x and dest_y - # then break the loop + self.generatemouseevent(current_x, current_y, 'abs') + if step == steps: break return 1 diff --git a/ldtpd/page_tab_list.py b/ldtpd/page_tab_list.py index 1da9f93..f034a3d 100644 --- a/ldtpd/page_tab_list.py +++ b/ldtpd/page_tab_list.py @@ -19,8 +19,8 @@ Headers in this file shall remain intact. """ import pyatspi -from utils import Utils -from server_exception import LdtpServerException +from .utils import Utils +from .server_exception import LdtpServerException class PageTabList(Utils): def selecttab(self, window_name, object_name, tab_name): diff --git a/ldtpd/table.py b/ldtpd/table.py index 025b712..3ca5f0a 100644 --- a/ldtpd/table.py +++ b/ldtpd/table.py @@ -21,9 +21,9 @@ import re import time import pyatspi -from utils import Utils -from server_exception import LdtpServerException -from keypress_actions import KeyComboAction, KeyPressAction, KeyReleaseAction +from .utils import Utils +from .server_exception import LdtpServerException +from .keypress_actions import KeyComboAction, KeyPressAction, KeyReleaseAction class Table(Utils): def getrowcount(self, window_name, object_name): @@ -407,7 +407,7 @@ def setcellvalue(self, window_name, object_name, row_index, except NotImplementedError: iaction = None if iaction: - for i in xrange(iaction.nActions): + for i in range(iaction.nActions): # If the cell is toggle type if re.match('toggle', iaction.getName(i), re.I): iaction.doAction(i) @@ -434,7 +434,7 @@ def setcellvalue(self, window_name, object_name, row_index, iaction = None self._grab_focus(cell) if iaction: - for i in xrange(iaction.nActions): + for i in range(iaction.nActions): # If the cell is toggle type if re.match('toggle', iaction.getName(i), re.I): iaction.doAction(i) diff --git a/ldtpd/text.py b/ldtpd/text.py index 5768db2..20699b2 100644 --- a/ldtpd/text.py +++ b/ldtpd/text.py @@ -21,10 +21,10 @@ import re import pyatspi -from utils import Utils +from .utils import Utils from fnmatch import translate as glob_trans -from server_exception import LdtpServerException -from keypress_actions import KeyComboAction, KeyPressAction, KeyReleaseAction +from .server_exception import LdtpServerException +from .keypress_actions import KeyComboAction, KeyPressAction, KeyReleaseAction class Text(Utils): def generatekeyevent(self, data): diff --git a/ldtpd/utils.py b/ldtpd/utils.py index 1c07bcd..8310a6a 100644 --- a/ldtpd/utils.py +++ b/ldtpd/utils.py @@ -31,6 +31,8 @@ import logging.handlers try: # If we have gtk3+ gobject introspection, use that + import gi + gi.require_version('Gdk', '3.0') from gi.repository import Gdk gtk3 = True except: @@ -38,9 +40,9 @@ import gtk gtk3 = False from re import match as re_match -from constants import abbreviated_roles +from .constants import abbreviated_roles from fnmatch import translate as glob_trans -from server_exception import LdtpServerException +from .server_exception import LdtpServerException importStatGrab = False try: @@ -377,6 +379,8 @@ def _list_guis(self): except LookupError: # If the window doesn't exist, remove from the cached list self.cached_apps.remove(app) + except GeneratorExit: + raise except: # In at-spi2 gi._glib.GError exception is thrown # If the window doesn't exist, remove from the cached list @@ -472,7 +476,7 @@ def _glob_match(self, pattern, string): """ # regex flags Multi-line, Unicode, Locale return bool(re_match(glob_trans(pattern), string, - re.M | re.U | re.L)) + re.M | re.U )) def _match_name_to_acc(self, name, acc, classType = None): """ @@ -691,7 +695,7 @@ def _add_appmap_data(self, obj, parent, child_index): key_binding = '' try: iaction = obj.queryAction() - for j in xrange(iaction.nActions): + for j in range(iaction.nActions): if iaction.getKeyBinding(j) != '': key_binding = iaction.getKeyBinding(j) break @@ -815,7 +819,7 @@ def _click_object(self, obj, action = '(click|press|activate)'): raise LdtpServerException( 'Object does not have an Action interface') else: - for i in xrange(iaction.nActions): + for i in range(iaction.nActions): if self._ldtp_debug: print(iaction.getName(i)) if re.match(action, iaction.getName(i), re.I): diff --git a/ldtpd/value.py b/ldtpd/value.py index aa3b277..7dbda25 100644 --- a/ldtpd/value.py +++ b/ldtpd/value.py @@ -21,8 +21,8 @@ import time import pyatspi -from utils import Utils -from server_exception import LdtpServerException +from .utils import Utils +from .server_exception import LdtpServerException class Value(Utils): def setvalue(self, window_name, object_name, data): diff --git a/ldtpd/waiters.py b/ldtpd/waiters.py index 1401006..129676e 100644 --- a/ldtpd/waiters.py +++ b/ldtpd/waiters.py @@ -20,11 +20,13 @@ """ wnckModule = False -from utils import Utils +from .utils import Utils import re import time try: # If we have gtk3+ gobject introspection, use that + import gi + gi.require_version('Wnck', '3.0') from gi.repository import Wnck as wnck from gi.repository import Gtk as gtk from gi.repository import GObject as gobject diff --git a/ldtpd/xmlrpc_daemon.py b/ldtpd/xmlrpc_daemon.py index e1e83e1..95027d7 100644 --- a/ldtpd/xmlrpc_daemon.py +++ b/ldtpd/xmlrpc_daemon.py @@ -22,11 +22,10 @@ import os import re import time -import core -from core import Ldtpd -from twisted.web import xmlrpc -import xmlrpclib -from log import logger +from .core import Ldtpd +import xmlrpc as xmlrpc +from .log import logger +from twisted.web import xmlrpc as tw_xmlrpc if 'LDTP_COMMAND_DELAY' in os.environ: delay = os.environ['LDTP_COMMAND_DELAY'] @@ -36,7 +35,7 @@ _ldtp_debug = os.environ.get('LDTP_DEBUG', None) _ldtp_debug_file = os.environ.get('LDTP_DEBUG_FILE', None) -class XMLRPCLdtpd(Ldtpd, xmlrpc.XMLRPC, object): +class XMLRPCLdtpd(Ldtpd, tw_xmlrpc.XMLRPC, object): def __new__(cls, *args, **kwargs): for symbol in dir(Ldtpd): if symbol.startswith('_'): @@ -48,7 +47,7 @@ def __new__(cls, *args, **kwargs): return object.__new__(cls, *args, **kwargs) def __init__(self): - xmlrpc.XMLRPC.__init__(self, allowNone = True) + tw_xmlrpc.XMLRPC.__init__(self, allowNone = True) Ldtpd.__init__(self) def _listFunctions(self): @@ -61,7 +60,7 @@ def _listFunctions(self): # If LDTP_DEBUG env set, then print verbose info on console def _ebRender(self, failure): """Custom error render method (used by our XMLRPC objects)""" - if isinstance(failure.value, xmlrpclib.Fault): + if isinstance(failure.value, tw_xmlrpc.Fault): return failure.value if hasattr(failure, 'getErrorMessage'): @@ -69,13 +68,13 @@ def _ebRender(self, failure): else: value = 'error' - return xmlrpclib.Fault(self.FAILURE, value) + return tw_xmlrpc.Fault(self.FAILURE, value) def render_POST(self, request): request.content.seek(0, 0) request.setHeader("content-type", "text/xml") try: - args, functionPath = xmlrpclib.loads(request.content.read()) + args, functionPath = xmlrpc.client.loads(request.content.read()) if args and isinstance(args[-1], dict): # Passing args and kwargs to _ldtp_callback # fail, so using self, kind of work around ! @@ -98,7 +97,7 @@ def render_POST(self, request): else: kwargs = {} except Exception as e: - f = xmlrpc.Fault( + f = tw_xmlrpc.Fault( self.FAILURE, "Can't deserialize input: %s" % (e,)) self._cbRender(f, request) else: @@ -108,13 +107,13 @@ def render_POST(self, request): function = self.lookupProcedure(functionPath) else: function = self._getFunction(functionPath) - except xmlrpc.Fault as f: + except tw_xmlrpc.Fault as f: self._cbRender(f, request) else: if _ldtp_debug: debug_st = '%s(%s)' % \ (functionPath, - ', '.join(map(repr, args) + \ + ', '.join(list(map(repr, args)) + \ ['%s=%s' % (k, repr(v)) \ for k, v in kwargs.items()])) print(debug_st) @@ -122,9 +121,9 @@ def render_POST(self, request): if _ldtp_debug_file: with open(_ldtp_debug_file, "a") as fp: fp.write(debug_st) - xmlrpc.defer.maybeDeferred(function, *args, + tw_xmlrpc.defer.maybeDeferred(function, *args, **kwargs).\ addErrback(self._ebRender).\ addCallback(self._cbRender, request) - return xmlrpc.server.NOT_DONE_YET + return tw_xmlrpc.server.NOT_DONE_YET diff --git a/ldtpme/__init__.py b/ldtpme/__init__.py index 4cdbb5e..1c532a6 100644 --- a/ldtpme/__init__.py +++ b/ldtpme/__init__.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # -*- coding: utf-8 -*- # vim: ai ts=4 sts=4 et sw=4 nu ''' diff --git a/ldtputils/__init__.py b/ldtputils/__init__.py index 419dba0..a707792 100644 --- a/ldtputils/__init__.py +++ b/ldtputils/__init__.py @@ -42,7 +42,7 @@ def imagecompare(imgfile1, imgfile2): for row in data: seq += list(row) - for i in xrange(0, imgdiffcrop.size[0] * imgdiffcrop.size[1] * 3, 3): + for i in range(0, imgdiffcrop.size[0] * imgdiffcrop.size[1] * 3, 3): if seq[i] != 0 or seq[i+1] != 0 or seq[i+2] != 0: diffcount = diffcount + 1.0 diff --git a/scripts/ldtp b/scripts/ldtp index 13a87ae..6c89874 100755 --- a/scripts/ldtp +++ b/scripts/ldtp @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 """ LDTP v2 ldtp executable @@ -47,6 +47,6 @@ def parse_cmd_line_option(): options = parse_cmd_line_option() try: - ldtpd.main(options.port) + ldtpd.main(options.port) except KeyboardInterrupt: - pass + pass diff --git a/setup.py b/setup.py index 61f0b71..8c72b30 100644 --- a/setup.py +++ b/setup.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 """ LDTP v2 Core. @@ -23,7 +23,7 @@ from setuptools import setup setup(name="ldtp", - version="3.5.1", + version="3.6.0", description="Linux Desktop Testing Project Version 2", maintainer="Nagappan Alagappan", maintainer_email="nagappan@gmail.com",