Diff
Modified: trunk/Tools/ChangeLog (279380 => 279381)
--- trunk/Tools/ChangeLog 2021-06-29 19:07:43 UTC (rev 279380)
+++ trunk/Tools/ChangeLog 2021-06-29 19:27:13 UTC (rev 279381)
@@ -1,5 +1,39 @@
2021-06-29 Jonathan Bedard <jbed...@apple.com>
+ [webkitcorepy] Add NestedFuzzyDict
+ https://bugs.webkit.org/show_bug.cgi?id=227150
+ <rdar://problem/79475464>
+
+ Reviewed by Dewei Zhu.
+
+ * Scripts/libraries/webkitcorepy/setup.py: Bump version.
+ * Scripts/libraries/webkitcorepy/webkitcorepy/__init__.py: Ditto.
+ * Scripts/libraries/webkitcorepy/webkitcorepy/nested_fuzzy_dict.py: Added.
+ (NestedFuzzyDict):
+ (NestedFuzzyDict.assert_valid_key): Ensure that the provided key is fuzz-able.
+ (NestedFuzzyDict.__init__): Construct the object the same way a dictionary is constructed.
+ (NestedFuzzyDict.__getitem__): Split provided keyname and fuzzy match the second part.
+ (NestedFuzzyDict.get): Ditto.
+ (NestedFuzzyDict.getitem): Return the complete keyname and value.
+ (NestedFuzzyDict.__setitem__): Add value to dictionary.
+ (NestedFuzzyDict.update): Given a dictionary, insert it's contents into this object.
+ (NestedFuzzyDict.keys): Iterate through all keys in the object.
+ (NestedFuzzyDict.values): Iterate through all values in the object.
+ (NestedFuzzyDict.items): Iterate through all key/value pairs in the object.
+ (NestedFuzzyDict.dict): Return a standard dictionary with the contents of this object.
+ (NestedFuzzyDict.__repr__):
+ (NestedFuzzyDict.__str__):
+ * Scripts/libraries/webkitcorepy/webkitcorepy/tests/nested_fuzzy_dict_unittest.py: Added.
+ (TestNestedFuzzyDict):
+ (TestNestedFuzzyDict.test_constructor):
+ (TestNestedFuzzyDict.test_index):
+ (TestNestedFuzzyDict.test_get):
+ (TestNestedFuzzyDict.test_getitem):
+ (TestNestedFuzzyDict.test_set):
+ (TestNestedFuzzyDict.test_dict):
+
+2021-06-29 Jonathan Bedard <jbed...@apple.com>
+
[webkitcorepy] Add MeasureTime python tool
https://bugs.webkit.org/show_bug.cgi?id=227313
<rdar://problem/79689588>
Modified: trunk/Tools/Scripts/libraries/webkitcorepy/setup.py (279380 => 279381)
--- trunk/Tools/Scripts/libraries/webkitcorepy/setup.py 2021-06-29 19:07:43 UTC (rev 279380)
+++ trunk/Tools/Scripts/libraries/webkitcorepy/setup.py 2021-06-29 19:27:13 UTC (rev 279381)
@@ -30,7 +30,7 @@
setup(
name='webkitcorepy',
- version='0.6.1',
+ version='0.7.0',
description='Library containing various Python support classes and functions.',
long_description=readme(),
classifiers=[
Modified: trunk/Tools/Scripts/libraries/webkitcorepy/webkitcorepy/__init__.py (279380 => 279381)
--- trunk/Tools/Scripts/libraries/webkitcorepy/webkitcorepy/__init__.py 2021-06-29 19:07:43 UTC (rev 279380)
+++ trunk/Tools/Scripts/libraries/webkitcorepy/webkitcorepy/__init__.py 2021-06-29 19:27:13 UTC (rev 279381)
@@ -37,8 +37,9 @@
from webkitcorepy.task_pool import TaskPool
from webkitcorepy.credentials import credentials
from webkitcorepy.measure_time import MeasureTime
+from webkitcorepy.nested_fuzzy_dict import NestedFuzzyDict
-version = Version(0, 6, 1)
+version = Version(0, 7, 0)
from webkitcorepy.autoinstall import Package, AutoInstall
if sys.version_info > (3, 0):
Added: trunk/Tools/Scripts/libraries/webkitcorepy/webkitcorepy/nested_fuzzy_dict.py (0 => 279381)
--- trunk/Tools/Scripts/libraries/webkitcorepy/webkitcorepy/nested_fuzzy_dict.py (rev 0)
+++ trunk/Tools/Scripts/libraries/webkitcorepy/webkitcorepy/nested_fuzzy_dict.py 2021-06-29 19:27:13 UTC (rev 279381)
@@ -0,0 +1,115 @@
+# Copyright (C) 2021 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+from webkitcorepy.string_utils import unicode
+
+
+class NestedFuzzyDict(object):
+ @classmethod
+ def assert_valid_key(cls, key):
+ if not any((isinstance(key, str), isinstance(key, unicode), isinstance(key, bytes))):
+ raise ValueError("'{}' is not a valid key for a NestedDict".format(type(key)))
+
+ def __init__(self, primary_size=None, **kwargs):
+ self.primary_size = int(primary_size or 6)
+ self._data = dict()
+ self.update(dict(**kwargs))
+
+ def getitem(self, keyname, value=None):
+ self.assert_valid_key(keyname)
+ key_a, key_b = keyname[:self.primary_size], keyname[self.primary_size:]
+ found = None
+ for key, result in self._data.get(key_a, dict()).items():
+ if key.startswith(key_b):
+ if found:
+ raise KeyError("Multiple values match '{}'".format(keyname))
+ found = key_a + key
+ value = result
+ return found, value
+
+ def __getitem__(self, keyname):
+ key, value = self.getitem(keyname)
+ if key:
+ return value
+ raise KeyError(keyname)
+
+ def get(self, keyname, value=None):
+ return self.getitem(keyname, value)[1]
+
+ def __setitem__(self, key, value):
+ self.assert_valid_key(key)
+ self._data.setdefault(key[:self.primary_size], dict())[key[self.primary_size:]] = value
+
+ def __delitem__(self, keyname):
+ self.assert_valid_key(keyname)
+ key_a, key_b = keyname[:self.primary_size], keyname[self.primary_size:]
+ to_remove = []
+ for key, result in self._data.get(key_a, dict()).items():
+ if key.startswith(key_b):
+ to_remove.append(key)
+ if not to_remove:
+ raise KeyError(keyname)
+ for key in to_remove:
+ del self._data[key_a][key]
+ if not self._data.get(key_a, True):
+ del self._data[key_a]
+
+ def __contains__(self, keyname):
+ key_a, key_b = keyname[:self.primary_size], keyname[self.primary_size:]
+ for key, result in self._data.get(key_a, dict()).items():
+ if key.startswith(key_b):
+ return True
+ return False
+
+ def update(self, data):
+ for key, value in data.items():
+ self[key] = value
+
+ def __len__(self):
+ return sum([len(values) for values in self._data.values()])
+
+ def keys(self):
+ for key_a, values in self._data.items():
+ for key_b in values.keys():
+ yield key_a + key_b
+
+ def values(self):
+ for values in self._data.values():
+ for value in values.values():
+ yield value
+
+ def items(self):
+ for key_a, values in self._data.items():
+ for key_b, value in values.items():
+ yield key_a + key_b, value
+
+ def dict(self):
+ result = dict()
+ for key, value in self.items():
+ result[key] = value
+ return result
+
+ def __repr__(self):
+ return self.dict().__repr__()
+
+ def __str__(self):
+ return self.dict().__str__()
Added: trunk/Tools/Scripts/libraries/webkitcorepy/webkitcorepy/tests/nested_fuzzy_dict_unittest.py (0 => 279381)
--- trunk/Tools/Scripts/libraries/webkitcorepy/webkitcorepy/tests/nested_fuzzy_dict_unittest.py (rev 0)
+++ trunk/Tools/Scripts/libraries/webkitcorepy/webkitcorepy/tests/nested_fuzzy_dict_unittest.py 2021-06-29 19:27:13 UTC (rev 279381)
@@ -0,0 +1,95 @@
+# Copyright (C) 2021 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import unittest
+
+from webkitcorepy import NestedFuzzyDict
+
+
+class TestNestedFuzzyDict(unittest.TestCase):
+ def test_constructor(self):
+ d = NestedFuzzyDict(value_a=1, value_b=2, other_value=3)
+ self.assertEqual(sorted(list(d.values())), sorted((1, 2, 3)))
+ self.assertEqual(sorted(list(d.keys())), sorted(('value_a', 'value_b', 'other_value')))
+ self.assertEqual(
+ sorted(list(d.items())),
+ sorted((('value_a', 1), ('value_b', 2), ('other_value', 3))),
+ )
+
+ def test_index(self):
+ d = NestedFuzzyDict(value_a=1, value_b=2, other_value=3)
+ self.assertEqual(d['value_a'], 1)
+ self.assertEqual(d['value_b'], 2)
+ self.assertEqual(d['other_'], 3)
+
+ with self.assertRaises(KeyError):
+ self.assertEqual(d['nothing'], None)
+
+ with self.assertRaises(KeyError):
+ self.assertEqual(d['value'], None)
+
+ def test_get(self):
+ d = NestedFuzzyDict(value_a=1, value_b=2, other_value=3)
+ self.assertEqual(d.get('value_a'), 1)
+ self.assertEqual(d.get('value_b'), 2)
+ self.assertEqual(d.get('other_'), 3)
+ self.assertEqual(d.get('nothing'), None)
+
+ with self.assertRaises(KeyError):
+ self.assertEqual(d.get('value_'), None)
+
+ def test_getitem(self):
+ d = NestedFuzzyDict(value_a=1, value_b=2, other_value=3)
+ self.assertEqual(d.getitem('value_a'), ('value_a', 1))
+ self.assertEqual(d.getitem('value_b'), ('value_b', 2))
+ self.assertEqual(d.getitem('other_'), ('other_value', 3))
+ self.assertEqual(d.getitem('nothing'), (None, None))
+
+ with self.assertRaises(KeyError):
+ self.assertEqual(d.getitem('value_'), (None, None))
+
+ def test_set(self):
+ d = NestedFuzzyDict()
+ self.assertEqual(d.get('somelongvalue'), None)
+ d['somelongvalue'] = 1
+ self.assertEqual(d.get('somelongvalue'), 1)
+ self.assertEqual(d.get('somelong'), 1)
+
+ def test_delitem(self):
+ d = NestedFuzzyDict(value_a=1, value_b=2, other_value=3)
+ del d['other_value']
+ self.assertEqual(len(d), 2)
+ del d['value_']
+ self.assertEqual(len(d), 0)
+
+ def test_contains(self):
+ d = NestedFuzzyDict(value_a=1, value_b=2, other_value=3)
+ self.assertTrue('value_a' in d)
+ self.assertTrue('value_' in d)
+ self.assertFalse('content' in d)
+
+ def test_len(self):
+ self.assertEqual(len(NestedFuzzyDict(value_a=1, value_b=2, other_value=3)), 3)
+
+ def test_dict(self):
+ d = NestedFuzzyDict(value_a=1, value_b=2, other_value=3)
+ self.assertDictEqual(d.dict(), dict(value_a=1, value_b=2, other_value=3))