Add types.is_set() to test whether an arbitrary object is a set as defined by new_sets.bzl. (#181)
* Add sets.is_set() to test whether an arbitrary object is a set.
Since using sets requires special API, it can be useful to determine
whether an object is a set so special handling can be used.
For example, if a method wants to be able to take a list or a set.
diff --git a/lib/BUILD b/lib/BUILD
index 8ae8259..d5c8983 100644
--- a/lib/BUILD
+++ b/lib/BUILD
@@ -40,7 +40,9 @@
bzl_library(
name = "new_sets",
srcs = ["new_sets.bzl"],
- deps = [":dicts"],
+ deps = [
+ ":dicts",
+ ],
)
bzl_library(
diff --git a/lib/new_sets.bzl b/lib/new_sets.bzl
index a213cad..06e2058 100644
--- a/lib/new_sets.bzl
+++ b/lib/new_sets.bzl
@@ -18,6 +18,9 @@
if you pass it an sequence: `sets.make([1, 2, 3])`. This returns a struct containing all of the
values as keys in a dictionary - this means that all passed in values must be hashable. The
values in the set can be retrieved using `sets.to_list(my_set)`.
+
+ An arbitrary object can be tested whether it is a set generated by `sets.make()` or not with the
+ `types.is_set()` method in types.bzl.
"""
load(":dicts.bzl", "dicts")
@@ -33,6 +36,8 @@
Returns:
A set containing the passed in values.
"""
+ # If you change the structure of a set, you need to also update the _is_set method
+ # in types.bzl.
elements = elements if elements else []
return struct(_values = {e: None for e in elements})
@@ -233,4 +238,5 @@
remove = _remove,
repr = _repr,
str = _repr,
+ # is_set is declared in types.bzl
)
diff --git a/lib/types.bzl b/lib/types.bzl
index 7824893..db1ca18 100644
--- a/lib/types.bzl
+++ b/lib/types.bzl
@@ -21,6 +21,7 @@
_a_tuple_type = type(())
_an_int_type = type(1)
_a_depset_type = type(depset())
+_a_struct_type = type(struct())
def _a_function():
pass
@@ -126,6 +127,17 @@
"""
return type(v) == _a_depset_type
+def _is_set(v):
+ """Returns True if v is a set created by sets.make().
+
+ Args:
+ v: The value whose type should be checked.
+
+ Returns:
+ True if v was created by sets.make(), False otherwise.
+ """
+ return type(v) == _a_struct_type and hasattr(v, "_values") and _is_dict(v._values)
+
types = struct(
is_list = _is_list,
is_string = _is_string,
@@ -136,4 +148,5 @@
is_dict = _is_dict,
is_function = _is_function,
is_depset = _is_depset,
+ is_set = _is_set,
)
diff --git a/tests/types_tests.bzl b/tests/types_tests.bzl
index 6681d1c..aaf7cab 100644
--- a/tests/types_tests.bzl
+++ b/tests/types_tests.bzl
@@ -15,6 +15,7 @@
load("//lib:types.bzl", "types")
load("//lib:unittest.bzl", "asserts", "unittest")
+load("//lib:new_sets.bzl", "sets")
def _a_function():
"""A dummy function for testing."""
@@ -215,6 +216,21 @@
is_depset_test = unittest.make(_is_depset_test)
+def _is_set_test(ctx):
+ """Unit test for types.is_set."""
+ env = unittest.begin(ctx)
+
+ asserts.true(env, types.is_set(sets.make()))
+ asserts.true(env, types.is_set(sets.make([1])))
+ asserts.false(env, types.is_set(None))
+ asserts.false(env, types.is_set({}))
+ asserts.false(env, types.is_set(struct(foo = 1)))
+ asserts.false(env, types.is_set(struct(_values = "not really values")))
+
+ return unittest.end(env)
+
+is_set_test = unittest.make(_is_set_test)
+
def types_test_suite():
"""Creates the test targets and test suite for types.bzl tests."""
unittest.suite(
@@ -228,4 +244,5 @@
is_dict_test,
is_function_test,
is_depset_test,
+ is_set_test,
)