mirror of
https://github.com/gristlabs/grist-core.git
synced 2024-10-27 20:44:07 +00:00
(core) Make Python tests pass in Python 3.11
Summary: Mostly just changes to tests to make them more flexible. Test Plan: Python tests pass locally with 3.10 and 3.11. Making tests run in CI on these versions will happen in grist-core. Reviewers: paulfitz Reviewed By: paulfitz Subscribers: paulfitz Differential Revision: https://phab.getgrist.com/D3978
This commit is contained in:
parent
a77170c4bd
commit
d8b2dcbb55
@ -52,7 +52,10 @@ class AutocompleteContext(object):
|
||||
}
|
||||
for key, value in six.iteritems(self._context):
|
||||
if value and callable(value):
|
||||
if six.PY2:
|
||||
argspec = inspect.formatargspec(*inspect.getargspec(value))
|
||||
else:
|
||||
argspec = str(inspect.signature(value)) # pylint: disable=no-member
|
||||
self._functions[key] = Completion(key, argspec, is_grist_func(value))
|
||||
|
||||
for key, value in self._context.copy().items():
|
||||
|
@ -1,4 +1,5 @@
|
||||
import datetime
|
||||
import sys
|
||||
|
||||
import test_engine
|
||||
import testsamples
|
||||
@ -69,16 +70,13 @@ class TestCompletion(test_engine.EngineTestCase):
|
||||
self.assertEqual(self.autocomplete("valu", "Schools", "lastModifier"),
|
||||
["value"])
|
||||
# Should have same type as column.
|
||||
self.assertGreaterEqual(
|
||||
set(self.autocomplete("value.", "Schools", "lastModifier")),
|
||||
self.assert_autocomplete_includes("value.", "Schools", "lastModifier",
|
||||
{'value.startswith(', 'value.replace(', 'value.title('}
|
||||
)
|
||||
self.assertGreaterEqual(
|
||||
set(self.autocomplete("value.", "Schools", "lastModified")),
|
||||
self.assert_autocomplete_includes("value.", "Schools", "lastModified",
|
||||
{'value.month', 'value.strftime(', 'value.replace('}
|
||||
)
|
||||
self.assertGreaterEqual(
|
||||
set(self.autocomplete("value.m", "Schools", "lastModified")),
|
||||
self.assert_autocomplete_includes("value.m", "Schools", "lastModified",
|
||||
{'value.month', 'value.minute'}
|
||||
)
|
||||
|
||||
@ -159,13 +157,13 @@ class TestCompletion(test_engine.EngineTestCase):
|
||||
def test_function(self):
|
||||
self.assertEqual(self.autocomplete("MEDI", "Address", "city"),
|
||||
[('MEDIAN', '(value, *more_values)', True)])
|
||||
self.assertEqual(self.autocomplete("ma", "Address", "city"), [
|
||||
self.assert_autocomplete_includes("ma", "Address", "city", {
|
||||
('MAX', '(value, *more_values)', True),
|
||||
('MAXA', '(value, *more_values)', True),
|
||||
'map(',
|
||||
'math',
|
||||
'max(',
|
||||
])
|
||||
})
|
||||
|
||||
def test_member(self):
|
||||
self.assertEqual(self.autocomplete("datetime.tz", "Address", "city"),
|
||||
@ -294,34 +292,28 @@ class TestCompletion(test_engine.EngineTestCase):
|
||||
|
||||
def test_suggest_column_type_methods(self):
|
||||
# Should treat columns as correct types.
|
||||
self.assertGreaterEqual(
|
||||
set(self.autocomplete("$firstName.", "Students", "firstName")),
|
||||
self.assert_autocomplete_includes("$firstName.", "Students", "firstName",
|
||||
{'$firstName.startswith(', '$firstName.replace(', '$firstName.title('}
|
||||
)
|
||||
self.assertGreaterEqual(
|
||||
set(self.autocomplete("$birthDate.", "Students", "lastName")),
|
||||
self.assert_autocomplete_includes("$birthDate.", "Students", "lastName",
|
||||
{'$birthDate.month', '$birthDate.strftime(', '$birthDate.replace('}
|
||||
)
|
||||
self.assertGreaterEqual(
|
||||
set(self.autocomplete("$lastVisit.m", "Students", "firstName")),
|
||||
self.assert_autocomplete_includes("$lastVisit.m", "Students", "firstName",
|
||||
{'$lastVisit.month', '$lastVisit.minute'}
|
||||
)
|
||||
self.assertGreaterEqual(
|
||||
set(self.autocomplete("$school.", "Students", "firstName")),
|
||||
self.assert_autocomplete_includes("$school.", "Students", "firstName",
|
||||
{'$school.address', '$school.name', '$school.yearFounded', '$school.budget'}
|
||||
)
|
||||
self.assertEqual(self.autocomplete("$school.year", "Students", "lastName"),
|
||||
['$school.yearFounded'])
|
||||
self.assertGreaterEqual(
|
||||
set(self.autocomplete("$yearFounded.", "Schools", "budget")),
|
||||
self.assert_autocomplete_includes("$yearFounded.", "Schools", "budget",
|
||||
{
|
||||
'$yearFounded.denominator', # Only integers have this
|
||||
'$yearFounded.bit_length(', # and this
|
||||
'$yearFounded.real'
|
||||
}
|
||||
)
|
||||
self.assertGreaterEqual(
|
||||
set(self.autocomplete("$budget.", "Schools", "budget")),
|
||||
self.assert_autocomplete_includes("$budget.", "Schools", "budget",
|
||||
{'$budget.is_integer(', '$budget.real'} # Only floats have this
|
||||
)
|
||||
|
||||
@ -331,8 +323,7 @@ class TestCompletion(test_engine.EngineTestCase):
|
||||
self.autocomplete("$school.name.st", "Students", "firstName"),
|
||||
['$school.name.startswith(', '$school.name.strip(']
|
||||
)
|
||||
self.assertGreaterEqual(
|
||||
set(self.autocomplete("$school.yearFounded.","Students", "firstName")),
|
||||
self.assert_autocomplete_includes("$school.yearFounded.","Students", "firstName",
|
||||
{
|
||||
'$school.yearFounded.denominator',
|
||||
'$school.yearFounded.bit_length(',
|
||||
@ -498,6 +489,20 @@ class TestCompletion(test_engine.EngineTestCase):
|
||||
else:
|
||||
return results
|
||||
|
||||
def assert_autocomplete_includes(self, formula, table, column, expected, user=None, row_id=None):
|
||||
completions = self.autocomplete(formula, table, column, user=user, row_id=row_id)
|
||||
|
||||
def replace_completion(completion):
|
||||
if isinstance(completion, str) and completion.endswith('()'):
|
||||
# Python 3.10+ autocompletes the closing paren for methods with no arguments.
|
||||
# This allows the test to check for `somestring.title(` and work across Python versions.
|
||||
assert sys.version_info >= (3, 10)
|
||||
return completion[:-1]
|
||||
return completion
|
||||
|
||||
completions = set(replace_completion(completion) for completion in completions)
|
||||
self.assertGreaterEqual(completions, expected)
|
||||
|
||||
def test_example_values(self):
|
||||
self.assertEqual(
|
||||
self.autocomplete("$", "Schools", "name", row_id=1),
|
||||
|
@ -2,6 +2,7 @@ import difflib
|
||||
import functools
|
||||
import json
|
||||
import logging
|
||||
import sys
|
||||
import unittest
|
||||
from collections import namedtuple
|
||||
from pprint import pprint
|
||||
@ -273,7 +274,16 @@ class EngineTestCase(unittest.TestCase):
|
||||
self.assertIsInstance(exc.error, type_)
|
||||
self.assertEqual(exc._message, message)
|
||||
if tracebackRegexp:
|
||||
self.assertRegex(exc.details, tracebackRegexp)
|
||||
traceback_string = exc.details
|
||||
if sys.version_info >= (3, 11) and type_ != SyntaxError:
|
||||
# Python 3.11+ adds lines with only spaces and ^ to indicate the location of the error.
|
||||
# We remove those lines to make the test work with both old and new versions.
|
||||
# This doesn't apply to SyntaxError, which has those lines in all versions.
|
||||
traceback_string = "\n".join(
|
||||
line for line in traceback_string.splitlines()
|
||||
if set(line) != {" ", "^"}
|
||||
)
|
||||
self.assertRegex(traceback_string.strip(), tracebackRegexp.strip())
|
||||
|
||||
def assertViews(self, list_of_views):
|
||||
"""
|
||||
|
@ -37,7 +37,7 @@ schema_data = [
|
||||
[28, "country", "Text", False, "'US'", "country", ''],
|
||||
[29, "region", "Any", True,
|
||||
"{'US': 'North America', 'UK': 'Europe'}.get(rec.country, 'N/A')", "region", ''],
|
||||
[30, "badSyntax", "Any", True, "for a in b\n10", "", ""],
|
||||
[30, "badSyntax", "Any", True, "for a in\n10", "", ""],
|
||||
]]
|
||||
]
|
||||
|
||||
@ -72,11 +72,10 @@ class TestGenCode(unittest.TestCase):
|
||||
generated = gcode.get_user_text()
|
||||
if six.PY3:
|
||||
saved_sample = saved_sample.replace(
|
||||
"raise SyntaxError('invalid syntax', ('usercode', 1, 11, u'for a in b'))",
|
||||
"raise SyntaxError('invalid syntax', ('usercode', 1, 9, u'for a in'))",
|
||||
"raise SyntaxError('invalid syntax\\n\\n"
|
||||
"A `SyntaxError` occurs when Python cannot understand your code.\\n\\n"
|
||||
"You wrote a `for` loop but\\nforgot to add a colon `:` at the end\\n\\n', "
|
||||
"('usercode', 1, 11, 'for a in b'))"
|
||||
"A `SyntaxError` occurs when Python cannot understand your code.\\n\\n', "
|
||||
"('usercode', 1, 9, 'for a in'))"
|
||||
)
|
||||
self.assertEqual(generated, saved_sample, "Generated code doesn't match sample:\n" +
|
||||
"".join(difflib.unified_diff(generated.splitlines(True),
|
||||
|
@ -61,8 +61,8 @@ class Address:
|
||||
return {'US': 'North America', 'UK': 'Europe'}.get(rec.country, 'N/A')
|
||||
|
||||
def badSyntax(rec, table):
|
||||
# for a in b
|
||||
# for a in
|
||||
# 10
|
||||
raise SyntaxError('invalid syntax', ('usercode', 1, 11, u'for a in b'))
|
||||
raise SyntaxError('invalid syntax', ('usercode', 1, 9, u'for a in'))
|
||||
======================================================================
|
||||
"""
|
||||
|
Loading…
Reference in New Issue
Block a user