diff --git a/jpype/_pykeywords.py b/jpype/_pykeywords.py index 70e10856d..a438b80d4 100644 --- a/jpype/_pykeywords.py +++ b/jpype/_pykeywords.py @@ -70,7 +70,7 @@ def pysafe(s: str) -> typing.Optional[str]: Python that is guaranteed to not collide with the Python grammar. """ - if s.startswith("__") and s.endswith('__'): + if s.startswith("__") and s.endswith("__") and len(s) >= 4: # Dunder methods should not be considered safe. # (see system defined names in the Python documentation # https://docs.python.org/3/reference/lexical_analysis.html#reserved-classes-of-identifiers diff --git a/test/harness/jpype/attr/TestKeywords.java b/test/harness/jpype/attr/TestKeywords.java new file mode 100644 index 000000000..03dd4e86e --- /dev/null +++ b/test/harness/jpype/attr/TestKeywords.java @@ -0,0 +1,30 @@ +/* **************************************************************************** + Licensed 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. + + See NOTICE file for details. +**************************************************************************** */ +package jpype.attr; + +public class TestKeywords +{ + + public String __leading_double_underscore() + { + return "foo"; + } + + public String __dunder_name__() + { + return "foo"; + } +} diff --git a/test/jpypetest/common.py b/test/jpypetest/common.py index 1177eaeb2..7dee50d8a 100644 --- a/test/jpypetest/common.py +++ b/test/jpypetest/common.py @@ -127,8 +127,6 @@ def setUp(self): jpype.startJVM(jvm_path, *args, convertStrings=self._convertStrings) self.jpype = jpype.JPackage('jpype') - if sys.version < '3': - self.assertCountEqual = self.assertItemsEqual def tearDown(self): pass diff --git a/test/jpypetest/test_keywords.py b/test/jpypetest/test_keywords.py index 381b7f101..debe4f8ac 100644 --- a/test/jpypetest/test_keywords.py +++ b/test/jpypetest/test_keywords.py @@ -20,6 +20,7 @@ import pytest import jpype +import common @pytest.mark.parametrize( @@ -29,6 +30,7 @@ # Print is no longer a keyword in Python 3, but still protected to # avoid API breaking in JPype v1. 'print', + '____', # Not allowed. ] ) def testPySafe__Keywords(identifier): @@ -48,7 +50,15 @@ def testPySafe__Keywords(identifier): 'notSpecial__', '_notSpecial_', '_not__special_', + '__', '___', # Technically these are fine. ]) def testPySafe__NotKeywords(identifier): safe = jpype._pykeywords.pysafe(identifier) assert safe == identifier + + +class AttributeTestCase(common.JPypeTestCase): + def testPySafe(self): + cls = jpype.JPackage("jpype").attr.TestKeywords + self.assertTrue(hasattr(cls, "__leading_double_underscore")) + self.assertFalse(hasattr(cls, "__dunder_name__"))