Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [2.7, 3.6, 3.9, pypy3]
python-version: [3.6, 3.9, pypy3]
rf-version: [3.1.2, 3.2.2]

steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }} with Robot Framework ${{ matrix.rf-version }}
uses: actions/setup-python@v1
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
Expand All @@ -27,7 +27,6 @@ jobs:
- name: Run flake8
run: |
flake8 --max-line-length=110 src/
if: matrix.python-version != '2.7'
- name: Run unit tests
run: |
python utest/run.py
Expand Down
10 changes: 5 additions & 5 deletions atest/DynamicTypesAnnotationsLibrary.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def wrapper(*args, **kwargs):
return actual_decorator


class CustomObject(object):
class CustomObject:

def __init__(self, x, y):
self.x = x
Expand Down Expand Up @@ -75,19 +75,19 @@ def keyword_with_webdriver(self, arg: CustomObject):

@keyword
def keyword_default_and_annotation(self: 'DynamicTypesAnnotationsLibrary', arg1: int, arg2: Union[bool, str] = False) -> str:
return '%s: %s, %s: %s' % (arg1, type(arg1), arg2, type(arg2))
return '{}: {}, {}: {}'.format(arg1, type(arg1), arg2, type(arg2))

@keyword(types={'arg': str})
def keyword_robot_types_and_annotations(self: 'DynamicTypesAnnotationsLibrary', arg: int):
return '%s: %s' % (arg, type(arg))
return '{}: {}'.format(arg, type(arg))

@keyword(types=None)
def keyword_robot_types_disabled_and_annotations(self, arg: int):
return '%s: %s' % (arg, type(arg))
return '{}: {}'.format(arg, type(arg))

@keyword(types={'arg1': str})
def keyword_robot_types_and_bool_hint(self, arg1, arg2: bool):
return '%s: %s, %s: %s' % (arg1, type(arg1), arg2, type(arg2))
return '{}: {}, {}: {}'.format(arg1, type(arg1), arg2, type(arg2))

@keyword
def keyword_exception_annotations(self: 'DynamicTypesAnnotationsLibrary', arg: 'NotHere'):
Expand Down
6 changes: 3 additions & 3 deletions atest/DynamicTypesLibrary.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def keyword_many_default_types(self, arg1=1, arg2='Foobar'):

@keyword
def keyword_none(self, arg=None):
return '%s: %s' % (arg, type(arg))
return '{}: {}'.format(arg, type(arg))

@keyword
def is_python_3(self):
Expand All @@ -74,8 +74,8 @@ def keyword_wrapped(self, number=1, arg=''):

@keyword
def varargs_and_kwargs(self, *args, **kwargs):
return '%s, %s' % (args, kwargs)
return '{}, {}'.format(args, kwargs)

@keyword
def keyword_booleans(self, arg1=True, arg2=False):
return '%s: %s, %s: %s' % (arg1, type(arg1), arg2, type(arg2))
return '{}: {}, {}: {}'.format(arg1, type(arg1), arg2, type(arg2))
2 changes: 1 addition & 1 deletion atest/ExtendExistingLibrary.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ def __init__(self):
self.add_library_components([ExtendingComponent()])


class ExtendingComponent(object):
class ExtendingComponent:

@keyword
def keyword_in_extending_library(self):
Expand Down
10 changes: 4 additions & 6 deletions atest/librarycomponents.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from __future__ import print_function

from robotlibcore import keyword


Expand All @@ -8,7 +6,7 @@ def function():
return 1


class Names(object):
class Names:
attribute = 'not keyword'

@keyword
Expand All @@ -31,7 +29,7 @@ def dont_touch_property(self):
raise RuntimeError('Should not touch property!!')


class Arguments(object):
class Arguments:

@keyword
def mandatory(self, arg1, arg2):
Expand Down Expand Up @@ -61,11 +59,11 @@ def format_args(self, *args, **kwargs):
def ru(item):
return repr(item).lstrip('u')
args = [ru(a) for a in args]
kwargs = ['%s=%s' % (k, ru(kwargs[k])) for k in sorted(kwargs)]
kwargs = ['{}={}'.format(k, ru(kwargs[k])) for k in sorted(kwargs)]
return ', '.join(args + kwargs)


class DocsAndTags(object):
class DocsAndTags:

@keyword
def one_line_doc(self):
Expand Down
19 changes: 18 additions & 1 deletion atest/moc_library.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
from typing import Optional

from robot.api.deco import keyword


class MockLibrary(object):
class MockLibrary:

def no_args(self):
pass
Expand All @@ -27,3 +29,18 @@ def default_only(self, named1='string1', named2=123):

def varargs_kwargs(self, *vargs, **kwargs):
pass

def named_only(self, *varargs, key1, key2):
pass

def named_only_with_defaults(self, *varargs, key1, key2, key3='default1', key4=True):
pass

def args_with_type_hints(self, arg1, arg2, arg3: str, arg4: None) -> bool:
pass

def self_and_keyword_only_types(x: 'MockLibrary', mandatory, *varargs: int, other: bool, **kwargs: int):
pass

def optional_none(self, xxx, arg1: Optional[str] = None, arg2: Optional[str] = None, arg3=False):
pass
19 changes: 0 additions & 19 deletions atest/moc_library_py3.py

This file was deleted.

14 changes: 6 additions & 8 deletions atest/run.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#!/usr/bin/env python

from __future__ import print_function

import platform
from os.path import abspath, dirname, join
Expand All @@ -19,23 +18,22 @@
sys.path.insert(0, join(curdir, '..', 'src'))
python_version = platform.python_version()
for variant in library_variants:
output = join(outdir, 'lib-%s-python-%s-robot-%s.xml' % (variant, python_version, rf_version))
output = join(outdir, 'lib-{}-python-{}-robot-{}.xml'.format(variant, python_version, rf_version))
rc = run(tests, name=variant, variable='LIBRARY:%sLibrary' % variant,
output=output, report=None, log=None, loglevel='debug')
if rc > 250:
sys.exit(rc)
process_output(output, verbose=False)
output = join(outdir, 'lib-DynamicTypesLibrary-python-%s-robot-%s.xml' % (python_version, rf_version))
exclude = 'py3' if sys.version_info < (3,) else ''
rc = run(tests_types, name='Types', output=output, report=None, log=None, loglevel='debug', exclude=exclude)
output = join(outdir, 'lib-DynamicTypesLibrary-python-{}-robot-{}.xml'.format(python_version, rf_version))
rc = run(tests_types, name='Types', output=output, report=None, log=None, loglevel='debug')
if rc > 250:
sys.exit(rc)
process_output(output, verbose=False)
print('\nCombining results.')
library_variants.append('DynamicTypesLibrary')
rc = rebot(*(join(outdir, 'lib-%s-python-%s-robot-%s.xml' % (variant, python_version, rf_version)) for variant in library_variants),
**dict(name='Acceptance Tests', outputdir=outdir, log='log-python-%s-robot-%s.html' % (python_version, rf_version),
report='report-python-%s-robot-%s.html' % (python_version, rf_version)))
rc = rebot(*(join(outdir, 'lib-{}-python-{}-robot-{}.xml'.format(variant, python_version, rf_version)) for variant in library_variants),
**dict(name='Acceptance Tests', outputdir=outdir, log='log-python-{}-robot-{}.html'.format(python_version, rf_version),
report='report-python-{}-robot-{}.html'.format(python_version, rf_version)))
if rc == 0:
print('\nAll tests passed/failed as expected.')
else:
Expand Down
5 changes: 2 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,12 @@
Development Status :: 5 - Production/Stable
License :: OSI Approved :: Apache Software License
Operating System :: OS Independent
Programming Language :: Python :: 2
Programming Language :: Python :: 2.7
Programming Language :: Python :: 3
Programming Language :: Python :: 3.6
Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
Programming Language :: Python :: 3 :: Only
Programming Language :: Python :: Implementation :: CPython
Programming Language :: Python :: Implementation :: PyPy
Topic :: Software Development :: Testing
Expand All @@ -41,7 +40,7 @@
keywords = 'robotframework testing testautomation library development',
platforms = 'any',
classifiers = CLASSIFIERS,
python_requires = '>=2.7.*, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, <4',
python_requires = '>=3.6, <4',
package_dir = {'': 'src'},
packages = find_packages('src'),
py_modules = ['robotlibcore'],
Expand Down
29 changes: 7 additions & 22 deletions src/robotlibcore.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@

import inspect
import os
import sys

from robot.utils import PY_VERSION

Expand All @@ -33,13 +32,12 @@
from robot.api.deco import keyword # noqa F401
from robot import __version__ as robot_version

PY2 = sys.version_info < (3,)
RF31 = robot_version < '3.2'

__version__ = '2.2.2.dev1'


class HybridCore(object):
class HybridCore:

def __init__(self, library_components):
self.keywords = {}
Expand Down Expand Up @@ -87,10 +85,7 @@ def __getattr__(self, name):
.format(type(self).__name__, name))

def __dir__(self):
if PY2:
my_attrs = dir(type(self)) + list(self.__dict__)
else:
my_attrs = super().__dir__()
my_attrs = super().__dir__()
return sorted(set(my_attrs) | set(self.attributes))

def get_keyword_names(self):
Expand Down Expand Up @@ -136,7 +131,7 @@ def get_keyword_source(self, keyword_name):
path = self.__get_keyword_path(method)
line_number = self.__get_keyword_line(method)
if path and line_number:
return '%s:%s' % (path, line_number)
return '{}:{}'.format(path, line_number)
if path:
return path
if line_number:
Expand All @@ -146,7 +141,7 @@ def get_keyword_source(self, keyword_name):
def __get_keyword_line(self, method):
try:
lines, line_number = inspect.getsourcelines(method)
except (OSError, IOError, TypeError):
except (OSError, TypeError):
return None
for increment, line in enumerate(lines):
if line.strip().startswith('def '):
Expand All @@ -160,7 +155,7 @@ def __get_keyword_path(self, method):
return None


class KeywordBuilder(object):
class KeywordBuilder:

@classmethod
def build(cls, function):
Expand All @@ -172,8 +167,6 @@ def build(cls, function):

@classmethod
def unwrap(cls, function):
if PY2:
return function
return inspect.unwrap(function)

@classmethod
Expand All @@ -192,8 +185,6 @@ def _get_arguments(cls, function):

@classmethod
def _get_arg_spec(cls, function):
if PY2:
return inspect.getargspec(function)
return inspect.getfullargspec(function)

@classmethod
Expand Down Expand Up @@ -224,15 +215,11 @@ def _get_var_args(cls, arg_spec):

@classmethod
def _get_kwargs(cls, arg_spec):
if PY2:
return ['**%s' % arg_spec.keywords] if arg_spec.keywords else []
return ['**%s' % arg_spec.varkw] if arg_spec.varkw else []

@classmethod
def _get_kw_only(cls, arg_spec):
kw_only_args = []
if PY2:
return kw_only_args
for arg in arg_spec.kwonlyargs:
if not arg_spec.kwonlydefaults or arg not in arg_spec.kwonlydefaults:
kw_only_args.append(arg)
Expand All @@ -244,7 +231,7 @@ def _get_kw_only(cls, arg_spec):
@classmethod
def _format_defaults(cls, arg, value):
if RF31:
return '%s=%s' % (arg, value)
return '{}={}'.format(arg, value)
return arg, value

@classmethod
Expand All @@ -258,8 +245,6 @@ def _get_types(cls, function):

@classmethod
def _get_typing_hints(cls, function):
if PY2:
return {}
function = cls.unwrap(function)
try:
hints = typing.get_type_hints(function)
Expand Down Expand Up @@ -314,7 +299,7 @@ def _get_defaults(cls, arg_spec):
return zip(names, arg_spec.defaults)


class KeywordSpecification(object):
class KeywordSpecification:

def __init__(self, argument_specification=None, documentation=None, argument_types=None):
self.argument_specification = argument_specification
Expand Down
2 changes: 1 addition & 1 deletion utest/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
curdir = dirname(abspath(__file__))
atest_dir = join(curdir, '..', 'atest')
python_version = platform.python_version()
xunit_report = join(atest_dir, 'results', 'xunit-python-%s-robot%s.xml' % (python_version, rf_version))
xunit_report = join(atest_dir, 'results', 'xunit-python-{}-robot{}.xml'.format(python_version, rf_version))
src = join(curdir, '..', 'src')
sys.path.insert(0, src)
sys.path.insert(0, atest_dir)
Expand Down
6 changes: 2 additions & 4 deletions utest/test_get_keyword_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

from DynamicLibrary import DynamicLibrary
from DynamicTypesLibrary import DynamicTypesLibrary
from robotlibcore import PY2


@pytest.fixture(scope='module')
Expand Down Expand Up @@ -46,18 +45,17 @@ def test_location_in_main(lib, lib_path):

def test_location_in_class(lib, lib_path_components):
source = lib.get_keyword_source('method')
assert source == '%s:15' % lib_path_components
assert source == '%s:13' % lib_path_components


@pytest.mark.skipif(PY2, reason='Only applicable on Python 3')
def test_decorator_wrapper(lib_types, lib_path_types):
source = lib_types.get_keyword_source('keyword_wrapped')
assert source == '%s:72' % lib_path_types


def test_location_in_class_custom_keyword_name(lib, lib_path_components):
source = lib.get_keyword_source('Custom name')
assert source == '%s:19' % lib_path_components
assert source == '%s:17' % lib_path_components


def test_no_line_number(lib, lib_path, when):
Expand Down
Loading