Skip to content

Commit b350167

Browse files
committed
add option to exclude names in wildcard search
1 parent 1cfa23f commit b350167

2 files changed

Lines changed: 123 additions & 3 deletions

File tree

gnss_lib_py/parsers/navdata.py

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -844,17 +844,26 @@ def in_rows(self, rows):
844844
raise KeyError(", ".join(missing_rows) + " row(s) are" \
845845
+ " missing from NavData object.")
846846

847-
def find_wildcard_indexes(self, wildcards, max_allow = None):
847+
def find_wildcard_indexes(self, wildcards, max_allow = None,
848+
excludes = None):
848849
"""Searches for indexes matching wildcard search input.
849850
850851
For example, a search for ``x_*_m`` would find ``x_rx_m`` or
851852
``x_sv_m`` or ``x_alpha_beta_gamma_m`` depending on the rows
852853
existing in the NavData instance.
853854
855+
The ``excludes`` variable allows you to exclude indexes when
856+
trying to match a wildcard. For example, if there are rows named
857+
``pr_raw_m``and ``pr_raw_sigma_m`` then the input
858+
``wildcards="pr_*_m", excludes=None`` would return
859+
``{"pr_*_m", ["pr_raw_m","pr_raw_sigma_m"]}`` but with the excludes
860+
parameter set, the input ``wildcards="pr_*_m", excludes="pr_*_sigma_m"``
861+
would only return ``{"pr_*_m", ["pr_raw_m"]}``
862+
854863
Will return an error no index is found matching the wildcard or
855864
if more than ``max_allow`` indexes are found.
856865
857-
Currently only allows for a single wildcard per index.
866+
Currently only allows for a single wildcard '*' per index.
858867
859868
Parameters
860869
----------
@@ -863,6 +872,10 @@ def find_wildcard_indexes(self, wildcards, max_allow = None):
863872
max_allow : int or None
864873
Maximum number of valid indexes to allow before throwing an
865874
error. If None, then no limit is placed.
875+
excludes : array-like or str
876+
List or string to exclude for each wildcard in wildcards.
877+
Must be the same length as wildcards. Allowed to include a
878+
wildcard '*' character but not necessary.
866879
867880
Returns
868881
-------
@@ -879,10 +892,29 @@ def find_wildcard_indexes(self, wildcards, max_allow = None):
879892
if not (isinstance(max_allow,int) or max_allow is None):
880893
raise TypeError("max_allow input in find_wildcard_indexes" \
881894
+ " must be an integer or None.")
895+
# handle exclude types
896+
if isinstance(excludes,str):
897+
excludes = [excludes]
898+
if excludes is None:
899+
excludes = [None] * len(wildcards)
900+
if not isinstance(excludes, (list,tuple,np.ndarray,set)):
901+
raise TypeError("excludes input in find_wildcard_indexes" \
902+
+ " must be array-like, single string, " \
903+
+ "or None for each wildcard")
904+
if len(excludes) != len(wildcards):
905+
raise TypeError("excludes input must match length of " \
906+
+ "wildcard input.")
907+
for ex_idx, exclude in enumerate(excludes):
908+
if exclude is None or isinstance(exclude,str):
909+
excludes[ex_idx] = [exclude]
910+
if not isinstance(excludes[ex_idx], (list,tuple,np.ndarray,set)):
911+
raise TypeError("excludes input in find_wildcard_indexes" \
912+
+ " must be array-like, single string, " \
913+
+ "or None for each wildcard")
882914

883915
wildcard_indexes = {}
884916

885-
for wildcard in wildcards:
917+
for wild_idx, wildcard in enumerate(wildcards):
886918
if not isinstance(wildcard,str):
887919
raise TypeError("wildcards must be strings")
888920
if wildcard.count("*") != 1:
@@ -891,6 +923,15 @@ def find_wildcard_indexes(self, wildcards, max_allow = None):
891923
indexes = [row for row in self.rows
892924
if row.startswith(wildcard.split("*",maxsplit=1)[0])
893925
and row.endswith(wildcard.split("*",maxsplit=1)[1])]
926+
if excludes[wild_idx] is not None:
927+
for exclude in excludes[wild_idx]:
928+
if exclude is not None:
929+
if '*' in exclude:
930+
indexes = [row for row in indexes
931+
if not (row.startswith(exclude.split("*",maxsplit=1)[0])
932+
and row.endswith(exclude.split("*",maxsplit=1)[1]))]
933+
else:
934+
indexes = [row for row in indexes if exclude != row]
894935
if max_allow is not None and len(indexes) > max_allow:
895936
raise KeyError("More than " + str(max_allow) \
896937
+ " possible row indexes for " + wildcard)

tests/parsers/test_navdata.py

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2125,6 +2125,85 @@ def test_find_wildcard_indexes(data):
21252125
multi.find_wildcard_indexes("x_*_m",max_allow)
21262126
assert "max_allow" in str(excinfo.value)
21272127

2128+
def test_find_wildcard_excludes(data):
2129+
"""Tests find_wildcard_indexes
2130+
2131+
"""
2132+
all_matching = data.rename({"names" : "x_alpha_m",
2133+
"integers" : "x_beta_m",
2134+
"floats" : "x_gamma_m",
2135+
"strings" : "x_zeta_m"})
2136+
2137+
# no exclusion
2138+
indexes = all_matching.find_wildcard_indexes("x_*_m",excludes=None)
2139+
assert indexes["x_*_m"] == ["x_alpha_m","x_beta_m",
2140+
"x_gamma_m","x_zeta_m"]
2141+
indexes = all_matching.find_wildcard_indexes("x_*_m",excludes=[None])
2142+
assert indexes["x_*_m"] == ["x_alpha_m","x_beta_m",
2143+
"x_gamma_m","x_zeta_m"]
2144+
2145+
# single exclusion
2146+
indexes = all_matching.find_wildcard_indexes("x_*_m",excludes="x_beta_m")
2147+
assert indexes["x_*_m"] == ["x_alpha_m","x_gamma_m","x_zeta_m"]
2148+
2149+
# two exclusion
2150+
indexes = all_matching.find_wildcard_indexes("x_*_m",
2151+
excludes=[["x_beta_m","x_zeta_m"]])
2152+
assert indexes["x_*_m"] == ["x_alpha_m","x_gamma_m"]
2153+
2154+
# all excluded
2155+
with pytest.raises(KeyError) as excinfo:
2156+
all_matching.find_wildcard_indexes("x_*_m",excludes=["x_*_m"])
2157+
assert "Missing " in str(excinfo.value)
2158+
assert "x_*_m" in str(excinfo.value)
2159+
2160+
2161+
multi = data.rename({"names" : "x_alpha_m",
2162+
"integers" : "x_beta_m",
2163+
"floats" : "y_alpha_deg",
2164+
"strings" : "y_beta_deg"})
2165+
2166+
# no exclusion
2167+
indexes = multi.find_wildcard_indexes(["x_*_m","y_*_deg"],
2168+
excludes=None)
2169+
assert indexes["x_*_m"] == ["x_alpha_m","x_beta_m"]
2170+
assert indexes["y_*_deg"] == ["y_alpha_deg","y_beta_deg"]
2171+
indexes = multi.find_wildcard_indexes(["x_*_m","y_*_deg"],
2172+
excludes=[None,None])
2173+
assert indexes["x_*_m"] == ["x_alpha_m","x_beta_m"]
2174+
assert indexes["y_*_deg"] == ["y_alpha_deg","y_beta_deg"]
2175+
2176+
# single exclusion
2177+
indexes = multi.find_wildcard_indexes(["x_*_m","y_*_deg"],
2178+
excludes=["x_alpha*",None])
2179+
assert indexes["x_*_m"] == ["x_beta_m"]
2180+
assert indexes["y_*_deg"] == ["y_alpha_deg","y_beta_deg"]
2181+
2182+
# double exclusion
2183+
indexes = multi.find_wildcard_indexes(["x_*_m","y_*_deg"],
2184+
excludes=["x_alpha*","y_beta*"])
2185+
assert indexes["x_*_m"] == ["x_beta_m"]
2186+
assert indexes["y_*_deg"] == ["y_alpha_deg"]
2187+
2188+
# must match length
2189+
with pytest.raises(TypeError) as excinfo:
2190+
multi.find_wildcard_indexes(["x_*_m","y_*_deg"],
2191+
excludes=[None])
2192+
assert "match length" in str(excinfo.value)
2193+
2194+
# must match length
2195+
with pytest.raises(TypeError) as excinfo:
2196+
multi.find_wildcard_indexes(["x_*_m","y_*_deg"],
2197+
excludes={"a":"dictionary"})
2198+
assert "array-like" in str(excinfo.value)
2199+
# must match length
2200+
with pytest.raises(TypeError) as excinfo:
2201+
multi.find_wildcard_indexes(["x_*_m","y_*_deg"],
2202+
excludes=[None,{"a":"dictionary"}])
2203+
assert "array-like" in str(excinfo.value)
2204+
2205+
2206+
21282207
@pytest.mark.parametrize('csv_path',
21292208
[
21302209
lazy_fixture("csv_dtypes"),

0 commit comments

Comments
 (0)