Skip to content

Commit

Permalink
Add utility function to report whether strings have glob characters i…
Browse files Browse the repository at this point in the history
…n them
  • Loading branch information
timj committed Sep 7, 2024
1 parent aa622dc commit 709d25a
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 4 deletions.
31 changes: 29 additions & 2 deletions python/lsst/daf/butler/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
import functools
import logging
import re
from collections.abc import Callable
from collections.abc import Callable, Iterable
from re import Pattern
from types import EllipsisType
from typing import Any, TypeVar
Expand Down Expand Up @@ -92,7 +92,7 @@ def stripIfNotNone(s: str | None) -> str | None:
return s


def globToRegex(expressions: str | EllipsisType | None | list[str]) -> list[str | Pattern] | EllipsisType:
def globToRegex(expressions: str | EllipsisType | None | Iterable[str]) -> list[str | Pattern] | EllipsisType:
"""Translate glob-style search terms to regex.
If a stand-alone '``*``' is found in ``expressions``, or expressions is
Expand Down Expand Up @@ -134,6 +134,33 @@ def globToRegex(expressions: str | EllipsisType | None | list[str]) -> list[str
return results


def has_globs(expressions: str | EllipsisType | None | Iterable[str]) -> bool:
"""Determine if the expressions have any glob wildcard characters.
If a stand-alone '``*``' is found in ``expressions``, or expressions is
empty or `None`, then the special value ``...`` will be returned,
indicating that any string will match.
Parameters
----------
expressions : `str` or `list` [`str`]
A list of glob-style pattern strings to check.
Returns
-------
has_globs : `bool`
`True` if any of the supplied strings contain glob patterns.
"""
expanded = globToRegex(expressions)
if expanded is ...:
return True

for result in expanded:
if not isinstance(result, str):
return True
return False


class _Marker:
"""Private class to use as a default value when you want to know that
a default parameter has been over-ridden.
Expand Down
14 changes: 12 additions & 2 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
from collections import namedtuple

from lsst.daf.butler import NamedKeyDict, NamedValueSet
from lsst.daf.butler.utils import globToRegex
from lsst.daf.butler.utils import globToRegex, has_globs

TESTDIR = os.path.dirname(__file__)

Expand Down Expand Up @@ -187,7 +187,9 @@ def testStarInList(self):
"""Test that if a one of the items in the expression list is a star
(stand-alone) then ``...`` is returned (which implies no restrictions)
"""
self.assertIs(globToRegex(["foo", "*", "bar"]), ...)
globs = ["foo", "*", "bar"]
self.assertIs(globToRegex(globs), ...)
self.assertTrue(has_globs(globs))

def testGlobList(self):
"""Test that a list of glob strings converts as expected to a regex and
Expand All @@ -196,6 +198,8 @@ def testGlobList(self):
# These strings should be returned unchanged.
strings = ["bar", "😺", "ingésτ", "ex]", "[xe", "[!no", "e[x"]
self.assertEqual(globToRegex(strings), strings)
self.assertFalse(has_globs(strings))
self.assertTrue(has_globs("ba*"))

# Globs with strings that match the glob and strings that do not.
tests = (
Expand All @@ -215,6 +219,12 @@ def testGlobList(self):
for no_match in no_matches:
self.assertIsNone(re.fullmatch(patterns[0], no_match))

# All of them are globs except "bar".
if glob == "bar":
self.assertFalse(has_globs(glob))
else:
self.assertTrue(has_globs(glob))


if __name__ == "__main__":
unittest.main()

0 comments on commit 709d25a

Please sign in to comment.