Skip to content

Commit 6ed8111

Browse files
authored
replacing "stringcase" python package with internal implementation + generated java and kotlin code (#34949)
* changing matter_idl functions * changing yaml runner functions * removing stringcase from config and requirement files * restyle * improve string handling * fixing generated java and kotlin code * regenerate idl golden image for test_generators.py * adding unit test * restyle * adding unit test to build.GN
1 parent 927f99a commit 6ed8111

File tree

145 files changed

+1437
-1311
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

145 files changed

+1437
-1311
lines changed

integrations/docker/images/stage-2/chip-build-efr32/requirements.txt

-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
# codegen.py build requirements
22
Jinja2==3.1.3
33
lark==1.1.7
4-
stringcase==1.2.0
54
# Sphinx dependencies (for slc-cli)
65
linkify-it-py==2.0.2
76
myst-parser==2.0.0

scripts/py_matter_idl/BUILD.gn

+1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ pw_python_package("matter_idl") {
5353

5454
tests = [
5555
"matter_idl/test_backwards_compatibility.py",
56+
"matter_idl/test_case_conversion.py",
5657
"matter_idl/test_data_model_xml.py",
5758
"matter_idl/test_matter_idl_parser.py",
5859
"matter_idl/test_generators.py",

scripts/py_matter_idl/matter_idl/generators/filters.py

+76-7
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
import stringcase
15+
import re
1616

1717

1818
def normalize_acronyms(s: str) -> str:
@@ -49,6 +49,75 @@ def lowfirst_except_acronym(s: str) -> str:
4949
return lowfirst(s)
5050

5151

52+
def to_snake_case(s: str) -> str:
53+
"""convert to snake case; all words are seperated by underscore and are lower case
54+
examples:
55+
FooBarBaz --> foo_bar_baz
56+
foo BarBaz --> foo_bar_baz
57+
FOOBarBaz --> foo_bar_baz
58+
_fooBar_Baz_ --> foo_bar_baz
59+
"""
60+
s = "" if s is None else str(s)
61+
62+
s = re.sub(r'([A-Z]+)([A-Z][a-z])', r'\1_\2', s)
63+
s = re.sub(r'([a-z\d])([A-Z])', r'\1_\2', s)
64+
s = re.sub(r'[\s\-]+', '_', s)
65+
66+
snake_case = s.lower()
67+
return snake_case.strip('_')
68+
69+
70+
def to_constant_case(s: str) -> str:
71+
"""convert to constant case; all words are seperated by underscore and are upper case
72+
similar to a snake case but with upper case
73+
examples:
74+
FooBarBaz --> FOO_BAR_BAZ
75+
foo BarBaz --> FOO_BAR_BAZ
76+
FOOBarBaz --> FOO_BAR_BAZ
77+
"""
78+
snake_case = to_snake_case(s)
79+
constant_case = snake_case.upper()
80+
return constant_case
81+
82+
83+
def to_spinal_case(s: str) -> str:
84+
"""convert to spinal case; all words sperated by hypen and are lower case
85+
similar to a snake case but with hyphen seperator instead of underscore
86+
examples:
87+
FooBarBaz --> foo-bar-baz
88+
foo BarBaz --> foo-bar-baz
89+
FOOBarBaz --> foo-bar-baz
90+
"""
91+
snake_case = to_snake_case(s)
92+
return snake_case.replace('_', '-')
93+
94+
95+
def to_pascal_case(s: str) -> str:
96+
"""convert to pascal case; with no spaces or underscore between words, first letter of all words is uppercase
97+
examples:
98+
fooBarBaz --> FooBarBaz
99+
foo BarBaz --> FooBarBaz
100+
FOOBar_Baz --> FooBarBaz
101+
"""
102+
103+
snake_case = to_snake_case(s)
104+
snake_case_split = snake_case.split('_')
105+
pascal_case = ''.join(word.capitalize() for word in snake_case_split)
106+
107+
return pascal_case
108+
109+
110+
def to_camel_case(s) -> str:
111+
"""convert to camel case; with no spaces or underscore between words, first word all lowercase and following words are uppercase
112+
same as pascal case but first letter is lower case
113+
examples:
114+
FooBarBaz --> fooBarBaz
115+
foo BarBaz --> fooBarBaz
116+
FOOBarBaz --> fooBarBaz
117+
"""
118+
return lowfirst(to_pascal_case(s))
119+
120+
52121
def RegisterCommonFilters(filtermap):
53122
"""
54123
Register filters that are NOT considered platform-generator specific.
@@ -59,12 +128,12 @@ def RegisterCommonFilters(filtermap):
59128
"""
60129

61130
# General casing for output naming
62-
filtermap['camelcase'] = stringcase.camelcase
63-
filtermap['capitalcase'] = stringcase.capitalcase
64-
filtermap['constcase'] = stringcase.constcase
65-
filtermap['pascalcase'] = stringcase.pascalcase
66-
filtermap['snakecase'] = stringcase.snakecase
67-
filtermap['spinalcase'] = stringcase.spinalcase
131+
filtermap['camelcase'] = to_camel_case
132+
filtermap['capitalcase'] = upfirst
133+
filtermap['constcase'] = to_constant_case
134+
filtermap['pascalcase'] = to_pascal_case
135+
filtermap['snakecase'] = to_snake_case
136+
filtermap['spinalcase'] = to_spinal_case
68137

69138
filtermap['normalize_acronyms'] = normalize_acronyms
70139
filtermap['lowfirst'] = lowfirst

scripts/py_matter_idl/matter_idl/generators/java/__init__.py

+7-7
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@
2020
from typing import List, Optional, Set
2121

2222
from matter_idl.generators import CodeGenerator, GeneratorStorage
23+
from matter_idl.generators.filters import upfirst
2324
from matter_idl.generators.type_definitions import (BasicInteger, BasicString, FundamentalType, IdlBitmapType, IdlEnumType, IdlType,
2425
ParseDataType, TypeLookupContext)
2526
from matter_idl.matter_idl_types import (Attribute, Cluster, Command, DataType, Field, FieldQuality, Idl, Struct, StructQuality,
2627
StructTag)
27-
from stringcase import capitalcase
2828

2929

3030
@dataclasses.dataclass
@@ -199,7 +199,7 @@ def DelegatedCallbackName(attr: Attribute, context: TypeLookupContext) -> str:
199199
if global_name:
200200
return 'Delegated{}AttributeCallback'.format(GlobalNameToJavaName(global_name))
201201

202-
return 'Delegated{}Cluster{}AttributeCallback'.format(context.cluster.name, capitalcase(attr.definition.name))
202+
return 'Delegated{}Cluster{}AttributeCallback'.format(context.cluster.name, upfirst(attr.definition.name))
203203

204204

205205
def ChipClustersCallbackName(attr: Attribute, context: TypeLookupContext) -> str:
@@ -212,7 +212,7 @@ def ChipClustersCallbackName(attr: Attribute, context: TypeLookupContext) -> str
212212
if global_name:
213213
return 'ChipClusters.{}AttributeCallback'.format(GlobalNameToJavaName(global_name))
214214

215-
return 'ChipClusters.{}Cluster.{}AttributeCallback'.format(context.cluster.name, capitalcase(attr.definition.name))
215+
return 'ChipClusters.{}Cluster.{}AttributeCallback'.format(context.cluster.name, upfirst(attr.definition.name))
216216

217217

218218
def CallbackName(attr: Attribute, context: TypeLookupContext) -> str:
@@ -228,11 +228,11 @@ def CallbackName(attr: Attribute, context: TypeLookupContext) -> str:
228228
global_name = FieldToGlobalName(attr.definition, context)
229229

230230
if global_name:
231-
return 'CHIP{}AttributeCallback'.format(capitalcase(global_name))
231+
return 'CHIP{}AttributeCallback'.format(upfirst(global_name))
232232

233233
return 'CHIP{}{}AttributeCallback'.format(
234-
capitalcase(context.cluster.name),
235-
capitalcase(attr.definition.name)
234+
upfirst(context.cluster.name),
235+
upfirst(attr.definition.name)
236236
)
237237

238238

@@ -262,7 +262,7 @@ def JavaAttributeCallbackName(attr: Attribute, context: TypeLookupContext) -> st
262262
if global_name:
263263
return '{}AttributeCallback'.format(GlobalNameToJavaName(global_name))
264264

265-
return '{}AttributeCallback'.format(capitalcase(attr.definition.name))
265+
return '{}AttributeCallback'.format(upfirst(attr.definition.name))
266266

267267

268268
def IsFieldGlobalName(field: Field, context: TypeLookupContext) -> bool:

scripts/py_matter_idl/matter_idl/generators/kotlin/__init__.py

+7-7
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@
2020
from typing import List, Optional, Set
2121

2222
from matter_idl.generators import CodeGenerator, GeneratorStorage
23+
from matter_idl.generators.filters import upfirst
2324
from matter_idl.generators.type_definitions import (BasicInteger, BasicString, FundamentalType, IdlBitmapType, IdlEnumType, IdlType,
2425
ParseDataType, TypeLookupContext)
2526
from matter_idl.matter_idl_types import (Attribute, Cluster, Command, DataType, Field, FieldQuality, Idl, Struct, StructQuality,
2627
StructTag)
27-
from stringcase import capitalcase
2828

2929

3030
@dataclasses.dataclass
@@ -160,7 +160,7 @@ def DelegatedCallbackName(attr: Attribute, context: TypeLookupContext) -> str:
160160
if global_name:
161161
return 'Delegated{}AttributeCallback'.format(GlobalNameToJavaName(global_name))
162162

163-
return 'Delegated{}Cluster{}AttributeCallback'.format(context.cluster.name, capitalcase(attr.definition.name))
163+
return 'Delegated{}Cluster{}AttributeCallback'.format(context.cluster.name, upfirst(attr.definition.name))
164164

165165

166166
def ChipClustersCallbackName(attr: Attribute, context: TypeLookupContext) -> str:
@@ -173,7 +173,7 @@ def ChipClustersCallbackName(attr: Attribute, context: TypeLookupContext) -> str
173173
if global_name:
174174
return 'ChipClusters.{}AttributeCallback'.format(GlobalNameToJavaName(global_name))
175175

176-
return 'ChipClusters.{}Cluster.{}AttributeCallback'.format(context.cluster.name, capitalcase(attr.definition.name))
176+
return 'ChipClusters.{}Cluster.{}AttributeCallback'.format(context.cluster.name, upfirst(attr.definition.name))
177177

178178

179179
def CallbackName(attr: Attribute, context: TypeLookupContext) -> str:
@@ -189,11 +189,11 @@ def CallbackName(attr: Attribute, context: TypeLookupContext) -> str:
189189
global_name = FieldToGlobalName(attr.definition, context)
190190

191191
if global_name:
192-
return 'CHIP{}AttributeCallback'.format(capitalcase(global_name))
192+
return 'CHIP{}AttributeCallback'.format(upfirst(global_name))
193193

194194
return 'CHIP{}{}AttributeCallback'.format(
195-
capitalcase(context.cluster.name),
196-
capitalcase(attr.definition.name)
195+
upfirst(context.cluster.name),
196+
upfirst(attr.definition.name)
197197
)
198198

199199

@@ -223,7 +223,7 @@ def JavaAttributeCallbackName(attr: Attribute, context: TypeLookupContext) -> st
223223
if global_name:
224224
return '{}'.format(GlobalNameToJavaName(global_name))
225225

226-
return '{}Attribute'.format(capitalcase(attr.definition.name))
226+
return '{}Attribute'.format(upfirst(attr.definition.name))
227227

228228

229229
def IsFieldGlobalName(field: Field, context: TypeLookupContext) -> bool:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
2+
import unittest
3+
4+
import matter_idl.generators.filters as case_convert
5+
6+
'''
7+
This file contains tests for checking five of the case conversion functions, notably: snake_case, CONSTANT_CASE, spinal-case, PascalCase and camelCase.
8+
9+
10+
'''
11+
inputs = [
12+
"FooBarBaz",
13+
"FOOBarBaz",
14+
"FOOBarBAZ",
15+
"fooBARBaz",
16+
"fooBarBAZ",
17+
"foo BarBaz",
18+
" FooBarBaz ",
19+
"foo_bar_baz",
20+
"FOO-bar-baz",
21+
"FOO_BAR_BAZ",
22+
"__FooBarBaz__",
23+
"_fooBar_Baz_",
24+
"foo_Bar Baz"
25+
]
26+
27+
28+
class TestSnakeCase(unittest.TestCase):
29+
def test_snake_case(self):
30+
expected = "foo_bar_baz"
31+
for input in inputs:
32+
converted = case_convert.to_snake_case(input)
33+
self.assertEqual(converted, expected, "they are not equal")
34+
35+
def test_constant_case(self):
36+
expected = "FOO_BAR_BAZ"
37+
for input in inputs:
38+
converted = case_convert.to_constant_case(input)
39+
self.assertEqual(converted, expected, "they are not equal")
40+
41+
def test_spinal_case(self):
42+
expected = "foo-bar-baz"
43+
for input in inputs:
44+
converted = case_convert.to_spinal_case(input)
45+
self.assertEqual(converted, expected, "they are not equal")
46+
47+
def test_pascal_case(self):
48+
expected = "FooBarBaz"
49+
for input in inputs:
50+
converted = case_convert.to_pascal_case(input)
51+
self.assertEqual(converted, expected, "they are not equal")
52+
53+
def test_camel_case(self):
54+
expected = "fooBarBaz"
55+
for input in inputs:
56+
converted = case_convert.to_camel_case(input)
57+
self.assertEqual(converted, expected, "they are not equal")
58+
59+
60+
if __name__ == '__main__':
61+
unittest.main()

scripts/py_matter_idl/matter_idl/tests/outputs/several_clusters/java/ChipStructs.java

+9-9
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,9 @@ public static class SecondClusterFabricDescriptorStruct {
3232
public String label;
3333
public Integer fabricIndex;
3434
private static final long ROOT_PUBLIC_KEY_ID = 1L;
35-
private static final long VENDOR_I_D_ID = 2L;
36-
private static final long FABRIC_I_D_ID = 3L;
37-
private static final long NODE_I_D_ID = 4L;
35+
private static final long VENDOR_ID_ID = 2L;
36+
private static final long FABRIC_ID_ID = 3L;
37+
private static final long NODE_ID_ID = 4L;
3838
private static final long LABEL_ID = 5L;
3939
private static final long FABRIC_INDEX_ID = 254L;
4040

@@ -57,9 +57,9 @@ public SecondClusterFabricDescriptorStruct(
5757
public StructType encodeTlv() {
5858
ArrayList<StructElement> values = new ArrayList<>();
5959
values.add(new StructElement(ROOT_PUBLIC_KEY_ID, new ByteArrayType(rootPublicKey)));
60-
values.add(new StructElement(VENDOR_I_D_ID, new UIntType(vendorID)));
61-
values.add(new StructElement(FABRIC_I_D_ID, new UIntType(fabricID)));
62-
values.add(new StructElement(NODE_I_D_ID, new UIntType(nodeID)));
60+
values.add(new StructElement(VENDOR_ID_ID, new UIntType(vendorID)));
61+
values.add(new StructElement(FABRIC_ID_ID, new UIntType(fabricID)));
62+
values.add(new StructElement(NODE_ID_ID, new UIntType(nodeID)));
6363
values.add(new StructElement(LABEL_ID, new StringType(label)));
6464
values.add(new StructElement(FABRIC_INDEX_ID, new UIntType(fabricIndex)));
6565

@@ -82,17 +82,17 @@ public static SecondClusterFabricDescriptorStruct decodeTlv(BaseTLVType tlvValue
8282
ByteArrayType castingValue = element.value(ByteArrayType.class);
8383
rootPublicKey = castingValue.value(byte[].class);
8484
}
85-
} else if (element.contextTagNum() == VENDOR_I_D_ID) {
85+
} else if (element.contextTagNum() == VENDOR_ID_ID) {
8686
if (element.value(BaseTLVType.class).type() == TLVType.UInt) {
8787
UIntType castingValue = element.value(UIntType.class);
8888
vendorID = castingValue.value(Integer.class);
8989
}
90-
} else if (element.contextTagNum() == FABRIC_I_D_ID) {
90+
} else if (element.contextTagNum() == FABRIC_ID_ID) {
9191
if (element.value(BaseTLVType.class).type() == TLVType.UInt) {
9292
UIntType castingValue = element.value(UIntType.class);
9393
fabricID = castingValue.value(Long.class);
9494
}
95-
} else if (element.contextTagNum() == NODE_I_D_ID) {
95+
} else if (element.contextTagNum() == NODE_ID_ID) {
9696
if (element.value(BaseTLVType.class).type() == TLVType.UInt) {
9797
UIntType castingValue = element.value(UIntType.class);
9898
nodeID = castingValue.value(Long.class);

scripts/py_matter_idl/matter_idl/tests/outputs/several_clusters/java/SecondClusterFabricDescriptorStruct.kt

+9-9
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,9 @@ class SecondClusterFabricDescriptorStruct (
4848
tlvWriter.apply {
4949
startStructure(tlvTag)
5050
put(ContextSpecificTag(TAG_ROOT_PUBLIC_KEY), rootPublicKey)
51-
put(ContextSpecificTag(TAG_VENDOR_I_D), vendorID)
52-
put(ContextSpecificTag(TAG_FABRIC_I_D), fabricID)
53-
put(ContextSpecificTag(TAG_NODE_I_D), nodeID)
51+
put(ContextSpecificTag(TAG_VENDOR_ID), vendorID)
52+
put(ContextSpecificTag(TAG_FABRIC_ID), fabricID)
53+
put(ContextSpecificTag(TAG_NODE_ID), nodeID)
5454
put(ContextSpecificTag(TAG_LABEL), label)
5555
put(ContextSpecificTag(TAG_FABRIC_INDEX), fabricIndex)
5656
endStructure()
@@ -59,18 +59,18 @@ class SecondClusterFabricDescriptorStruct (
5959

6060
companion object {
6161
private const val TAG_ROOT_PUBLIC_KEY = 1
62-
private const val TAG_VENDOR_I_D = 2
63-
private const val TAG_FABRIC_I_D = 3
64-
private const val TAG_NODE_I_D = 4
62+
private const val TAG_VENDOR_ID = 2
63+
private const val TAG_FABRIC_ID = 3
64+
private const val TAG_NODE_ID = 4
6565
private const val TAG_LABEL = 5
6666
private const val TAG_FABRIC_INDEX = 254
6767

6868
fun fromTlv(tlvTag: Tag, tlvReader: TlvReader) : SecondClusterFabricDescriptorStruct {
6969
tlvReader.enterStructure(tlvTag)
7070
val rootPublicKey = tlvReader.getByteArray(ContextSpecificTag(TAG_ROOT_PUBLIC_KEY))
71-
val vendorID = tlvReader.getUInt(ContextSpecificTag(TAG_VENDOR_I_D))
72-
val fabricID = tlvReader.getULong(ContextSpecificTag(TAG_FABRIC_I_D))
73-
val nodeID = tlvReader.getULong(ContextSpecificTag(TAG_NODE_I_D))
71+
val vendorID = tlvReader.getUInt(ContextSpecificTag(TAG_VENDOR_ID))
72+
val fabricID = tlvReader.getULong(ContextSpecificTag(TAG_FABRIC_ID))
73+
val nodeID = tlvReader.getULong(ContextSpecificTag(TAG_NODE_ID))
7474
val label = tlvReader.getString(ContextSpecificTag(TAG_LABEL))
7575
val fabricIndex = tlvReader.getUInt(ContextSpecificTag(TAG_FABRIC_INDEX))
7676

scripts/py_matter_idl/setup.cfg

-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ zip_safe = False
2424
install_requires=
2525
lark
2626
jinja2
27-
stringcase
2827

2928
[options.package_data]
3029
matter_idl =

scripts/setup/constraints.txt

-2
Original file line numberDiff line numberDiff line change
@@ -245,8 +245,6 @@ six==1.16.0
245245
# requests-file
246246
stack-data==0.6.2
247247
# via ipython
248-
stringcase==1.2.0
249-
# via -r requirements.build.txt
250248
tabulate==0.9.0
251249
# via -r requirements.memory.txt
252250
tornado==6.2

scripts/setup/requirements.build.txt

-1
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,3 @@ click
1111
# scripts/py_matter_idl/matter_idl
1212
jinja2
1313
lark
14-
stringcase

0 commit comments

Comments
 (0)