SENSSOFT-103 Supporting pylint, coverage and unit test reports.
diff --git a/docs/source/conf.py b/docs/source/conf.py
index 4cd8b2b..78bc943 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -11,7 +11,7 @@
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
-# limitations under the License.
+# limitations under the License.
# Apache UserALE documentation build configuration file, created by
# sphinx-quickstart on Fri Jun 24 16:58:43 2016.
@@ -25,14 +25,15 @@
# All configuration values have a default; values that are commented out
# serve to show the default.
-import sys, os
+import sys
+import os
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
# sys.path.insert(0, os.path.abspath('../../'))
# sys.path.insert (0, '../..')
-#
+
sys.path.insert(0, os.path.abspath('../..'))
from userale.version import __version__
@@ -64,7 +65,7 @@
source_suffix = '.rst'
# The encoding of source files.
-#source_encoding = 'utf-8-sig'
+# source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
@@ -92,9 +93,9 @@
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
-#today = ''
+# today = ''
# Else, today_fmt is used as the format for a strftime call.
-#today_fmt = '%B %d, %Y'
+# today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
@@ -103,27 +104,27 @@
# The reST default role (used for this markup: `text`) to use for all
# documents.
-#default_role = None
+# default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
-#add_function_parentheses = True
+# add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
-#add_module_names = True
+# add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
-#show_authors = False
+# show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
-#modindex_common_prefix = []
+# modindex_common_prefix = []
# If true, keep warnings as "system message" paragraphs in the built documents.
-#keep_warnings = False
+# keep_warnings = False
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = True
@@ -138,26 +139,26 @@
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
-#html_theme_options = {}
+# html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
-#html_theme_path = []
+# html_theme_path = []
# The name for this set of Sphinx documents.
# "<project> v<release> documentation" by default.
-#html_title = u'UserAle v1.0'
+# html_title = u'UserAle v1.0'
# A shorter title for the navigation bar. Default is the same as html_title.
-#html_short_title = None
+# html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
-#html_logo = None
+# html_logo = None
# The name of an image file (relative to this directory) to use as a favicon of
-# the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
-#html_favicon = None
+# html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
@@ -167,23 +168,23 @@
# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
# directly to the root of the documentation.
-#html_extra_path = []
+# html_extra_path = []
# If not None, a 'Last updated on:' timestamp is inserted at every page
# bottom, using the given strftime format.
# The empty string is equivalent to '%b %d, %Y'.
-#html_last_updated_fmt = None
+# html_last_updated_fmt = None
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
-#html_use_smartypants = True
+# html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
-#html_sidebars = {}
+# html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
-#html_additional_pages = {}
+# html_additional_pages = {}
# If false, no module index is generated.
html_domain_indices = False
@@ -192,86 +193,88 @@
html_use_index = False
# If true, the index is split into individual pages for each letter.
-#html_split_index = False
+# html_split_index = False
# If true, links to the reST sources are added to the pages.
html_show_sourcelink = False
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
-#html_show_sphinx = True
+# html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
-#html_show_copyright = True
+# html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
-#html_use_opensearch = ''
+# html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
-#html_file_suffix = None
+# html_file_suffix = None
# Language to be used for generating the HTML full-text search index.
# Sphinx supports the following languages:
# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja'
# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr', 'zh'
-#html_search_language = 'en'
+# html_search_language = 'en'
# A dictionary with options for the search language support, empty by default.
# 'ja' uses this config value.
# 'zh' user can custom change `jieba` dictionary path.
-#html_search_options = {'type': 'default'}
+# html_search_options = {'type': 'default'}
# The name of a javascript file (relative to the configuration directory) that
# implements a search results scorer. If empty, the default will be used.
-#html_search_scorer = 'scorer.js'
+# html_search_scorer = 'scorer.js'
# Output file base name for HTML help builder.
htmlhelp_basename = 'ApacheUserALE.PyQt5.doc'
# -- Options for LaTeX output ---------------------------------------------
-latex_elements = {
+# latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
-#'papersize': 'letterpaper',
+# 'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
-#'pointsize': '10pt',
+# 'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
-#'preamble': '',
+# 'preamble': '',
# Latex figure (float) alignment
-#'figure_align': 'htbp',
-}
+# 'figure_align': 'htbp',
+# }
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
- (master_doc, 'ApacheUserALE.PyQt5.tex', u'Apache UserALE.PyQt5 Documentation',
- u'Michelle Beard \\textless{}msbeard@apache.dot.org\\textgreater{}', 'manual'),
+ (master_doc,
+ 'UserALE.PyQt5.tex', u'Apache UserALE.PyQt5 Documentation',
+ u'Michelle Beard \\textless{}msbeard@apache.dot.org\\textgreater{}',
+ 'manual')
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
-#latex_logo = None
+# latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
-#latex_use_parts = False
+# latex_use_parts = False
# If true, show page references after internal links.
-#latex_show_pagerefs = False
+# latex_show_pagerefs = False
# If true, show URL addresses after external links.
-#latex_show_urls = False
+# latex_show_urls = False
# Documents to append as an appendix to all manuals.
-#latex_appendices = []
+# latex_appendices = []
# If false, no module index is generated.
-#latex_domain_indices = True
+# latex_domain_indices = True
# -- Options for manual page output ---------------------------------------
@@ -284,7 +287,7 @@
]
# If true, show URL addresses after external links.
-#man_show_urls = False
+# man_show_urls = False
# -- Options for Texinfo output -------------------------------------------
@@ -294,21 +297,22 @@
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'ApacheUserALE.PyQt5', u'Apache UserALE.PyQt5 Documentation',
- author, 'ApacheUserAle.PyQt5', 'Apache UserALE.PyQt5 provides an easy way to generate highly detailed log streams from a PyQt5 application.',
+ author, 'ApacheUserAle.PyQt5', 'Apache UserALE.PyQt5 provides an easy way \
+ to generate highly detailed log streams from a PyQt5 application.',
'Instrumentation'),
]
# Documents to append as an appendix to all manuals.
-#texinfo_appendices = []
+# texinfo_appendices = []
# If false, no module index is generated.
-#texinfo_domain_indices = True
+# texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
-#texinfo_show_urls = 'footnote'
+# texinfo_show_urls = 'footnote'
# If true, do not generate a @detailmenu in the "Top" node's menu.
-#texinfo_no_detailmenu = False
+# texinfo_no_detailmenu = False
# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {'https://docs.python.org/': None}
diff --git a/setup.cfg b/setup.cfg
index 10bbb43..390dda1 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -14,11 +14,15 @@
# limitations under the License.
[egg_info]
+tag_build = 0.1.6
tag_svn_revision = false
-[pytest]
-addopts = --ignore=setup.py --ignore=build --ignore=dist --doctest-modules
-norecursedirs=*.egg
+[aliases]
+test=pytest
+
+[tool:pytest]
+addopts = --ignore=setup.py --ignore=build --ignore=dist --junitxml=test-report.xml --cov-report xml --cov=userale userale/.
+norecursedirs=*.eggs *env .igt
[build_sphinx]
source-dir = docs
diff --git a/setup.py b/setup.py
index d54ed46..10b4290 100644
--- a/setup.py
+++ b/setup.py
@@ -14,67 +14,59 @@
# limitations under the License.
from setuptools import setup, find_packages
-from setuptools.command.test import test as TestCommand
-import io, os, sys
+import os
+import sys
+
if sys.version_info[:2] < (3, 5):
m = "Python 3.5 or later is required for UserAle (%d.%d detected)."
- raise ImportError (m % sys.version_info[:2])
+ raise ImportError(m % sys.version_info[:2])
if sys.argv[-1] == 'setup.py':
print ("To install, run 'python3 setup.py install'")
print ()
-
-# This is a plug-in for setuptools that will invoke py.test
-# when you run python setup.py test
-class PyTest (TestCommand):
- def finalize_options (self):
- TestCommand.finalize_options (self)
- self.test_args = []
- self.test_suite = True
- def run_tests (self):
- import pytest # import here, because outside the required eggs aren't loaded yet
- sys.exit (pytest.main (self.test_args))
# Get the version string
-def get_version ():
- basedir = os.path.dirname (__file__)
- with open (os.path.join (basedir, 'userale/version.py')) as f:
+def get_version():
+ basedir = os.path.dirname(__file__)
+ with open(os.path.join(basedir, 'userale/version.py')) as f:
version = {}
- exec (f.read (), version)
+ exec(f.read(), version)
return version['__version__']
- raise RuntimeError ('No version info found.')
+ raise RuntimeError('No version info found.')
-setup (
- name = 'Apache UserALE.PyQt5',
- version = get_version (),
- url = 'https://github.com/draperlaboratory/userale.pyqt5',
- license = 'Apache Software License 2.0',
- author = 'Michelle Beard',
- author_email = 'mbeard@draper.com',
- description = 'Apache UserALE.PyQt5 provides an easy way to generate highly detailed log streams from a PyQt5 application.',
- long_description = __doc__,
- classifiers = [
- 'Development Status :: 4 - Beta',
- 'Programming Language :: Python',
- 'Programming Language :: Python :: 3.5',
- 'Natural Language :: English',
- 'Environment :: Desktop Environment',
- 'Intended Audience :: Developers',
- 'License :: OSI Approved :: Apache Software License',
- 'Operating System :: OS Independent'
+
+setup(
+ name='Apache UserALE.PyQt5',
+ version=get_version(),
+ url='https://github.com/apache/incubator-senssoft-userale-pyqt5',
+ license='Apache Software License 2.0',
+ author='Michelle Beard',
+ author_email='msbeard@apache.org',
+ description='Apache UserALE.PyQt5 provides an easy way to generate highly\
+ detailed log streams from a PyQt5 application.',
+ long_description=__doc__,
+ classifiers=[
+ 'Development Status :: 4 - Beta',
+ 'Intended Audience :: Developers',
+ 'Intended Audience :: Science/Research',
+ 'License :: OSI Approved :: Apache Software License',
+ 'Natural Language :: English',
+ 'Operating System :: OS Independent',
+ 'Programming Language :: Python :: 3 :: Only',
+ 'Programming Language :: Python :: 3.5',
+ 'Programming Language :: Python :: 3.6',
+ 'Topic :: Desktop Environment',
+ 'Topic :: Scientific/Engineering :: Information Analysis'
],
- keywords = 'logs users interactions', # Separate with spaces
- packages = find_packages (exclude=['examples', 'tests']),
- include_package_data = True,
- zip_safe = False,
- tests_require = ['pytest'],
- cmdclass = {'test': PyTest},
- install_requires = ['pyqt5==5.6',
- 'requests>=2.0.0'
- ],
- entry_points = {
+ keywords='logs users interactions',
+ packages=find_packages(exclude=['examples', 'tests']),
+ include_package_data=True,
+ zip_safe=False,
+ tests_require=['pytest>=3.0.0', 'pytest-pylint', 'coverage'],
+ install_requires=['pyqt5==5.6', 'requests>=2.0.0'],
+ entry_points={
'console_scripts': [
'mouse = userale.examples.testapp:test_app',
'drag = userale.examples.testdragndrop:test_drag',
diff --git a/test_requirements.txt b/test_requirements.txt
new file mode 100644
index 0000000..3201881
--- /dev/null
+++ b/test_requirements.txt
@@ -0,0 +1,21 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+pylint==1.6.4
+pytest==3.0.3
+pytest-cov==2.4.0
+pytest-runner==2.9
+pytest-pylint
+coverage==4.2
diff --git a/userale/ale.py b/userale/ale.py
index b196e4b..e82a916 100644
--- a/userale/ale.py
+++ b/userale/ale.py
@@ -16,8 +16,7 @@
from userale.version import __version__
from userale.format import JsonFormatter
from PyQt5.QtCore import QObject, QEvent, QTimer
-from collections import Counter
-import datetime, time
+import time
import logging
import uuid
import atexit
@@ -25,12 +24,12 @@
_ = JsonFormatter
+
class Ale (QObject):
"""
ALE Library
"""
-
- def __init__(self,
+ def __init__(self,
output="userale.log",
user=None,
session=None,
@@ -38,19 +37,23 @@
toolversion=None,
keylog=False,
interval=5000,
- resolution=100,
+ resolution=100,
shutoff=[]):
"""
:param output: [str] The file or url path to which logs will be sent.
:param user: [str] Identifier for the user of the application.
- :param session: [str] Session tag to track same user with multiple sessions. If a session is not provided, one will be created.
+ :param session: [str] Session tag to track same user with \
+ multiple sessions. If a session is not provided, one will be created.
:param toolname: [str] The application name.
:param toolversion: [str] The application version.
- :param keylog: [bool] Should detailed key logs be recorded. Default is False.
- :param interval: [int] The minimum time interval in ms between batch transmission of logs. Default is 5000ms.
- :param resolution: [int] Delay in ms between instances of high frequency logs like mousemoves, scrolls, etc. Default is 100ms (10Hz). Entering 0 disables it.
+ :param keylog: [bool] Enable logging of keystrokes.
+ :param interval: [int] The minimum time interval in ms between
+ \batch transmission of logs. Default is 5000ms.
+ :param resolution: [int] Delay in ms between instances of high \
+ frequency logs like mousemoves, scrolls, etc. Default is 100ms \
+ (10Hz). Entering 0 disables it.
:param shutoff: [list] Turn off logging for specific events.
-
+
An example log will appear like this:
.. code-block:: python
@@ -76,7 +79,7 @@
self.output = output
self.user = user
# Autogenerate session id if session is not configured
- self.session = session if session is not None else str (uuid.uuid4 ())
+ self.session = session if session is not None else str(uuid.uuid4())
self.toolname = toolname
self.toolversion = toolversion
self.keylog = keylog
@@ -85,11 +88,11 @@
self.shutoff = shutoff
# Configure logging
- self.logger = logging.getLogger ('userale')
+ self.logger = logging.getLogger('userale')
self.logger.propagate = False
- self.logger.setLevel (logging.INFO)
- handler = logging.FileHandler (self.output)
- self.logger.addHandler (handler)
+ self.logger.setLevel(logging.INFO)
+ handler = logging.FileHandler(self.output)
+ self.logger.addHandler(handler)
# Mapping of all events to methods
self.map = {
@@ -110,76 +113,80 @@
}
# Turn on/off keylogging & remove specific filters
- for key in list (self.map):
- name = list (self.map[key]) [0]
- if name in self.shutoff or (not self.keylog and (name == 'keypress' or name == 'keyrelease')):
- del self.map [key]
+ for key in list(self.map):
+ name = list(self.map[key])[0]
+ if (name in self.shutoff or
+ (not self.keylog and
+ (name == 'keypress' or name == 'keyrelease'))):
+ del self.map[key]
- # Sample rate
+ # Sample rate
self.hfreq = [QEvent.MouseMove, QEvent.DragMove, QEvent.Scroll]
# Sample Timer
if self.resolution > 0:
- self.timer = QTimer ()
- self.timer.timeout.connect (self.aggregate)
- self.timer.start (self.resolution)
+ self.timer = QTimer()
+ self.timer.timeout.connect(self.aggregate)
+ self.timer.start(self.resolution)
# Batch transmission of logs
- self.intervalID = self.startTimer (self.interval)
+ self.intervalID = self.startTimer(self.interval)
# Temporary storage for logs
self.logs = []
self.hlogs = []
# Register Exit hanldler
- atexit.register (self.cleanup)
+ atexit.register(self.cleanup)
- def eventFilter (self, object, event):
+ def eventFilter(self, object, event):
'''
:param object: [QObject] The object being watched.
:param event: [QEvent] The event triggered by a user action.
- :return: [bool] Propagate filter up if other objects needs to be handled
-
+ :return: [bool] Propagate filter up if other events need to be handled
+
Filters events for the watched widget.
'''
data = None
- t = event.type ()
+ t = event.type()
- if t in self.map:
- # Handle leaf node
- if len(object.children ()) == 0:
- # if object.isWidgetType () and len(object.children ()) == 0:
- name = list (self.map [t].keys())[0]
- method = list (self.map [t].values())[0]
- data = method (name, event, object)
+ if t in self.map:
+ # Handle leaf node
+ if len(object.children()) == 0:
+ # if object.isWidgetType () and len(object.children ()) == 0:
+ name = list(self.map[t].keys())[0]
+ method = list(self.map[t].values())[0]
+ data = method(name, event, object)
# Handle window object
else:
- # How to handle events on windows? It comes before the child widgets in window?
- # Either an event actually ocurred on window or is an effect of event propagation.
+ # How to handle events on windows?
+ # It comes before the child widgets in window?
+ # Either an event actually ocurred on window or
+ # is an effect of event propagation.
pass
# Filter data to higher or lower priority list
if data is not None:
print (_(data))
- if self.resolution > 0 and t in self.hfreq and t in self.map: # data is in watched list and is a high frequency log
- self.hlogs.append (data)
+ # data is in watched list and is a high frequency log
+ if self.resolution > 0 and t in self.hfreq and t in self.map:
+ self.hlogs.append(data)
else:
- self.logs.append (data)
+ self.logs.append(data)
+ return super(Ale, self).eventFilter(object, event)
- return super (Ale, self).eventFilter (object, event)
-
- def cleanup (self):
+ def cleanup(self):
'''
Clean up any dangling logs in self.logs or self.hlogs
'''
if self.resolution > 0:
- self.aggregate ()
- self.dump ()
+ self.aggregate()
+ self.dump()
- def timerEvent (self, event):
+ def timerEvent(self, event):
'''
:param object: [list] List of events
:return: [void] Emit events to file
@@ -187,201 +194,199 @@
Routinely dump data to file or send over the network
'''
- self.dump ()
+ self.dump()
- def dump (self):
+ def dump(self):
'''
Write log data to file
'''
- if len (self.logs) > 0:
+ if len(self.logs) > 0:
# print ("dumping {} logs".format (len (self.logs)))
- self.logger.info (_(self.logs))
- self.logs = [] # Reset logs
+ self.logger.info(_(self.logs))
+ self.logs = [] # Reset logs
- def aggregate (self):
+ def aggregate(self):
'''
- Sample high frequency logs at self.resolution. High frequency logs are consolidated down to a single log event
+ Sample high frequency logs at self.resolution.
+ High frequency logs are consolidated down to a single log event
to be emitted later
'''
-
- if len (self.hlogs) > 0:
- # print ("agging {} logs".format (len (self.hlogs)))
- # Given target, path, location [median], return aggregate
- # agg_events = Counter (self.hlogs)
- # # Iterate over collapsed collection to generate a single log per event
- # # Location information is lost due to consolidation.
- # # @todo develop hashing funciton or new counter to generate avg x and avg y location
- # for event, counter in agg_events.items ():
- # # aggdata = self.__create_msg (event[0], event[1], event[2], details={"count" : counter})
- # aggdata = {"target": event[0], "type" : event[1], "details": {"count": counter}}
- # print (aggdata)
- # self.logs.append (aggdata)
- self.logs.append (random.choice (self.hlogs))
+
+ if len(self.hlogs) > 0:
+ self.logs.append(random.choice(self.hlogs))
self.hlogs = []
-
- def getSender (self, object):
+
+ def getSender(self, object):
'''
:param object: [QObject] The object being watched.
- :return: [QObject] The QObject
+ :return: [QObject] The QObject
Fetch the QObject who triggered the event
'''
sender = None
try:
- sender = object.sender () if object.sender() is not None else None
+ sender = object.sender() if object.sender() is not None else None
except:
pass
return sender
- def getSelector (self, object):
+ def getSelector(self, object):
"""
:param object: [QObject] The base class for all Qt objects.
:return: [str] The Qt object's name
- Get target object's name (object defined by user or object's meta class name). If object is null, return "Undefined".
+ Get target object's name. If object is null, return "Undefined".
"""
try:
- return object.objectName () if object.objectName () else object.staticMetaObject.className ()
+ return object.objectName() if object.objectName() else object.staticMetaObject.className()
except:
return "Undefined"
- def getLocation (self, event):
+ def getLocation(self, event):
"""
:param event: [QEvent] The base class for all event classes.
- :return: [dict] A dictionary representation of the x and y positions of the mouse cursor.
+ :return: [dict] A dict of the x and y positions of the mouse cursor.
- Grab the x and y position of the mouse cursor, relative to the widget that received the event.
+ Grab the x and y position of the mouse cursor,
+ relative to the widget that received the event.
"""
- try:
- return {"x" : event.pos ().x (), "y" : event.pos ().y ()}
+ try:
+ return {"x": event.pos().x(), "y": event.pos().y()}
except:
return None
- def getPath (self, object):
+ def getPath(self, object):
"""
:param object: [QObject] The base class for all Qt objects.
:return: [list] List of QObjects.
- Generate the entire object hierachy from root to leaf node.
+ Generate the entire object hierachy from root to leaf node.
"""
try:
if object.parent() is not None:
- return self.getPath (object.parent()) + [self.getSelector (object)]
+ return self.getPath(object.parent()) + [self.getSelector(object)]
else:
- return [self.getSelector (object)]
+ return [self.getSelector(object)]
except:
return "Undefined"
-
- def getClientTime (self):
+
+ def getClientTime(self):
"""
- :return: [str] String representation of the time the event was captured.
-
- Capture the time the event was captured in milliseconds since the UNIX epoch (January 1, 1970 00:00:00 UTC)
+ :return: [str] Time the event was captured.
+
+ Capture the time the event was captured in milliseconds
+ since the UNIX epoch (January 1, 1970 00:00:00 UTC)
"""
- return int (time.time() * 1000)
+ return int(time.time() * 1000)
- def handleMouseEvents (self, event_type, event, object):
+ def handleMouseEvents(self, event_type, event, object):
"""
- :param event_type: [str] The string representation of the type of event being triggered by the user.
+ :param event_type: [str] The type of event being triggered by the user.
:param event: [QEvent] The base class for all event classes.
:param object: [QObject] The base class for all Qt objects.
:return: [dict] A userale log describing a mouse event.
- Returns the userale log representing all mouse event data.
+ Returns the userale log representing all mouse event data.
"""
details = {}
- return self.__create_msg (event_type, event, object, details=details)
+ return self.__create_msg(event_type, event, object, details=details)
- def handleKeyEvents (self, event_type, event, object):
+ def handleKeyEvents(self, event_type, event, object):
"""
- :param event_type: [str] The string representation of the type of event being triggered by the user.
+ :param event_type: [str] The type of event being triggered by the user.
:param event: [QEvent] The base class for all event classes.
:param object: [QObject] The base class for all Qt objects.
:return: [dict] A userale log describing a key event.
- Returns the userale log representing all key events, including key name and key code.
+ Returns the userale log representing all key events,
+ including key name and key code.
"""
- details = {"key" : event.text (), "keycode" : event.key ()}
- return self.__create_msg (event_type, event, object, details=details)
+ details = {"key": event.text(), "keycode": event.key()}
+ return self.__create_msg(event_type, event, object, details=details)
- def handleDragEvents (self, event_type, event, object):
+ def handleDragEvents(self, event_type, event, object):
"""
- :param event_type: [str] The string representation of the type of event being triggered by the user.
+ :param event_type: [str] The type of event being triggered by the user.
:param event: [QEvent] The base class for all event classes.
:param object: [QObject] The base class for all Qt objects.
:return: [dict] A userale log describing a drag event.
- Returns the userale log representing all drag events.
+ Returns the userale log representing all drag events.
"""
details = {}
try:
- details ["source"] = self.getSelector (event.source ())
+ details["source"] = self.getSelector(event.source())
except:
- details ["source"] = None
+ details["source"] = None
- return self.__create_msg (event_type, event, object, details=details)
+ return self.__create_msg(event_type, event, object, details=details)
- def handleMoveEvents (self, event_type, event, object):
+ def handleMoveEvents(self, event_type, event, object):
"""
- :param event_type: [str] The string representation of the type of event being triggered by the user.
+ :param event_type: [str] The type of event being triggered by the user.
:param event: [QEvent] The base class for all event classes.
:param object: [QObject] The base class for all Qt objects.
:return: [dict] A userale log describing a drag event.
- Returns the userale log representing all move events.
+ Returns the userale log representing all move events.
"""
- details = {"oldPos" : {"x" : event.oldPos ().x (), "y" : event.oldPos ().y ()}}
- return self.__create_msg (event_type, event, object, details=details)
-
- def handleResizeEvents (self, event_type, event, object):
+ details = {"oldPos": {"x": event.oldPos().x(),
+ "y": event.oldPos().y()}}
+
+ return self.__create_msg(event_type, event, object, details=details)
+
+ def handleResizeEvents(self, event_type, event, object):
"""
- :param event_type: [str] The string representation of the type of event being triggered by the user.
+ :param event_type: [str] The type of event being triggered by the user.
:param event: [QEvent] The base class for all event classes.
:param object: [QObject] The base class for all Qt objects.
:return: [dict] A userale log describing a resize event.
- Returns the userale log representing all resize events.
+ Returns the userale log representing all resize events.
"""
- details = {"size" : {"height" : event.size ().height (), "width" : event.size ().width ()},
- "oldSize": {"height" : event.oldSize ().height (), "width" : event.oldSize ().width ()}}
- return self.__create_msg (event_type, event, object, details=details)
+ details = {"size": {"height": event.size().height(),
+ "width": event.size().width()},
+ "oldSize": {"height": event.oldSize().height(),
+ "width": event.oldSize().width()}}
- def handleScrollEvents (self, event_type, event, object):
+ return self.__create_msg(event_type, event, object, details=details)
+
+ def handleScrollEvents(self, event_type, event, object):
"""
- :param event_type: [str] The string representation of the type of event being triggered by the user.
+ :param event_type: [str] The type of event being triggered by the user.
:param event: [QEvent] The base class for all event classes.
:param object: [QObject] The base class for all Qt objects.
:return: [dict] A userale log describing a scroll event.
- Returns the userale log representing all scroll events.
+ Returns the userale log representing all scroll events.
"""
- return self.__create_msg (event_type, event, object)
+ return self.__create_msg(event_type, event, object)
- def __create_msg (self, event_type, event, object, details={}):
+ def __create_msg(self, event_type, event, object, details={}):
"""
Geneate UserAle log describing an event.
"""
data = {
- "target": self.getSelector (object),
- "path": self.getPath (object),
- "clientTime": self.getClientTime (),
- "location": self.getLocation (event),
- "type": event_type ,
+ "target": self.getSelector(object),
+ "path": self.getPath(object),
+ "clientTime": self.getClientTime(),
+ "location": self.getLocation(event),
+ "type": event_type,
"userAction": True, # legacy field
- "details" : details,
+ "details": details,
"userId": self.user,
"session": self.session,
"toolName": self.toolname,
diff --git a/userale/format.py b/userale/format.py
index 7b1c750..abf138d 100644
--- a/userale/format.py
+++ b/userale/format.py
@@ -13,20 +13,12 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import requests
-from requests.auth import HTTPBasicAuth, HTTPDigestAuth
-from requests.auth import AuthBase
-
import json
-# Logger will need to optinally handle authorization
-# through basic http auth, proxy, and SOCKS
class JsonFormatter (object):
- """
- """
- def __init__(self, data):
- self.data = data
+ def __init__(self, data):
+ self.data = data
- def __str__(self):
- return "%s" % (json.dumps (self.data, sort_keys=False))
+ def __str__(self):
+ return "%s" % (json.dumps(self.data, sort_keys=False))
diff --git a/userale/version.py b/userale/version.py
index 48782d9..2071510 100644
--- a/userale/version.py
+++ b/userale/version.py
@@ -19,4 +19,4 @@
and parsed by ``setup.py``.
"""
-__version__ = "0.1.5"
\ No newline at end of file
+__version__ = "0.1.6"