# Path: augur/util_support/date_disambiguator.py
# def tuple_to_date(year, month, day):
# def max_day_for_year_month(year, month):
# def resolve_uncertain_int(uncertain_string, min_or_max):
#     def __init__(self, uncertain_date, fmt="%Y-%m-%d", min_max_year=None):
#     def range(self):
#     def uncertain_date_components(self):
#     def fmt_components(self):
#     def regex(self):
#     def assert_only_less_significant_uncertainty(self):
# class DateDisambiguator:
# 
# Path: augur/util_support/date_disambiguator.py
# class DateDisambiguator:
#     """Transforms a date string with uncertainty into the range of possible dates."""
# 
#     def __init__(self, uncertain_date, fmt="%Y-%m-%d", min_max_year=None):
#         self.uncertain_date = uncertain_date
#         self.fmt = fmt
#         self.min_max_year = min_max_year
# 
#         self.assert_only_less_significant_uncertainty()
# 
#     def range(self):
#         min_date = tuple_to_date(
#             resolve_uncertain_int(self.uncertain_date_components["Y"], "min"),
#             resolve_uncertain_int(self.uncertain_date_components["m"], "min"),
#             resolve_uncertain_int(self.uncertain_date_components["d"], "min"),
#         )
# 
#         max_date = tuple_to_date(
#             resolve_uncertain_int(self.uncertain_date_components["Y"], "max"),
#             resolve_uncertain_int(self.uncertain_date_components["m"], "max"),
#             resolve_uncertain_int(self.uncertain_date_components["d"], "max"),
#         )
#         max_date = min(max_date, datetime.date.today())
# 
#         return (min_date, max_date)
# 
#     @property
#     @functools.lru_cache()
#     def uncertain_date_components(self):
#         matches = re.search(self.regex, self.uncertain_date)
# 
#         if matches is None:
#             raise ValueError(
#                 f"Malformed uncertain date `{self.uncertain_date}` for format `{self.fmt}`"
#             )
# 
#         return dict(zip(self.fmt_components, matches.groups()))
# 
#     @property
#     @functools.lru_cache()
#     def fmt_components(self):
#         # The `re` module doesn't capture repeated groups, so we'll do it without regexes
#         return [component[0] for component in self.fmt.split("%") if len(component) > 0]
# 
#     @property
#     def regex(self):
#         """
#         Returns regex defined by the format string.
#         Currently only supports %Y, %m, and %d.
#         """
#         return re.compile(
#             "^"
#             + self.fmt.replace("%Y", "(....)")
#             .replace("%m", "(..?)")
#             .replace("%d", "(..?)")
#             + "$"
#         )
# 
#     def assert_only_less_significant_uncertainty(self):
#         """
#         Raise an exception if a constrained digit appears in a less-significant place
#         than an uncertain digit.
# 
#         Assuming %Y-%m-%d, these patterns are valid:
#             2000-01-01
#             2000-01-XX
#             2000-XX-XX
# 
#         but this is invalid, because month is uncertain but day is constrained:
#             2000-XX-01
# 
#         These invalid cases are assumed to be unintended use of the tool.
#         """
#         if "X" in self.uncertain_date_components["Y"]:
#             if (
#                 self.uncertain_date_components["m"] != "XX"
#                 or self.uncertain_date_components["d"] != "XX"
#             ):
#                 raise ValueError(
#                     "Invalid date: Year contains uncertainty, so month and day must also be uncertain."
#                 )
#         elif "X" in self.uncertain_date_components["m"]:
#             if self.uncertain_date_components["d"] != "XX":
#                 raise ValueError(
#                     "Invalid date: Month contains uncertainty, so day must also be uncertain."
#                 )


import datetime
import pytest
from augur.util_support import date_disambiguator
from augur.util_support.date_disambiguator import DateDisambiguator
from freezegun import freeze_time
        ],
    )
    def test_range(self, date_str, expected_range):
        assert DateDisambiguator(date_str).range() == expected_range

    @pytest.mark.parametrize(
        "date_str, fmt",
        [
            ("2005-02-XX", "%Y-%m-%d"),
            ("2005/02/XX", "%Y/%m/%d"),
            ("2005-XX-02", "%Y-%d-%m"),
            ("200502XX", "%Y%m%d"),
        ],
    )
    def test_range_separators(self, date_str, fmt):
        assert DateDisambiguator(date_str, fmt=fmt).range() == (
            datetime.date(2005, 2, 1),
            datetime.date(2005, 2, 28),
        )

    @pytest.mark.parametrize(
        "date_str, expected_components",
        [
            ("2000-01-01", {"Y": "2000", "m": "01", "d": "01"}),
            ("2000-01-XX", {"Y": "2000", "m": "01", "d": "XX"}),
            ("2000-XX-XX", {"Y": "2000", "m": "XX", "d": "XX"}),
        ],
    )
    def test_uncertain_date_components(self, date_str, expected_components):
        assert (

# Path: augur/util_support/date_disambiguator.py
# def tuple_to_date(year, month, day):
# def max_day_for_year_month(year, month):
# def resolve_uncertain_int(uncertain_string, min_or_max):
#     def __init__(self, uncertain_date, fmt="%Y-%m-%d", min_max_year=None):
#     def range(self):
#     def uncertain_date_components(self):
#     def fmt_components(self):
#     def regex(self):
#     def assert_only_less_significant_uncertainty(self):
# class DateDisambiguator:
# 
# Path: augur/util_support/date_disambiguator.py
# class DateDisambiguator:
#     """Transforms a date string with uncertainty into the range of possible dates."""
# 
#     def __init__(self, uncertain_date, fmt="%Y-%m-%d", min_max_year=None):
#         self.uncertain_date = uncertain_date
#         self.fmt = fmt
#         self.min_max_year = min_max_year
# 
#         self.assert_only_less_significant_uncertainty()
# 
#     def range(self):
#         min_date = tuple_to_date(
#             resolve_uncertain_int(self.uncertain_date_components["Y"], "min"),
#             resolve_uncertain_int(self.uncertain_date_components["m"], "min"),
#             resolve_uncertain_int(self.uncertain_date_components["d"], "min"),
#         )
# 
#         max_date = tuple_to_date(
#             resolve_uncertain_int(self.uncertain_date_components["Y"], "max"),
#             resolve_uncertain_int(self.uncertain_date_components["m"], "max"),
#             resolve_uncertain_int(self.uncertain_date_components["d"], "max"),
#         )
#         max_date = min(max_date, datetime.date.today())
# 
#         return (min_date, max_date)
# 
#     @property
#     @functools.lru_cache()
#     def uncertain_date_components(self):
#         matches = re.search(self.regex, self.uncertain_date)
# 
#         if matches is None:
#             raise ValueError(
#                 f"Malformed uncertain date `{self.uncertain_date}` for format `{self.fmt}`"
#             )
# 
#         return dict(zip(self.fmt_components, matches.groups()))
# 
#     @property
#     @functools.lru_cache()
#     def fmt_components(self):
#         # The `re` module doesn't capture repeated groups, so we'll do it without regexes
#         return [component[0] for component in self.fmt.split("%") if len(component) > 0]
# 
#     @property
#     def regex(self):
#         """
#         Returns regex defined by the format string.
#         Currently only supports %Y, %m, and %d.
#         """
#         return re.compile(
#             "^"
#             + self.fmt.replace("%Y", "(....)")
#             .replace("%m", "(..?)")
#             .replace("%d", "(..?)")
#             + "$"
#         )
# 
#     def assert_only_less_significant_uncertainty(self):
#         """
#         Raise an exception if a constrained digit appears in a less-significant place
#         than an uncertain digit.
# 
#         Assuming %Y-%m-%d, these patterns are valid:
#             2000-01-01
#             2000-01-XX
#             2000-XX-XX
# 
#         but this is invalid, because month is uncertain but day is constrained:
#             2000-XX-01
# 
#         These invalid cases are assumed to be unintended use of the tool.
#         """
#         if "X" in self.uncertain_date_components["Y"]:
#             if (
#                 self.uncertain_date_components["m"] != "XX"
#                 or self.uncertain_date_components["d"] != "XX"
#             ):
#                 raise ValueError(
#                     "Invalid date: Year contains uncertainty, so month and day must also be uncertain."
#                 )
#         elif "X" in self.uncertain_date_components["m"]:
#             if self.uncertain_date_components["d"] != "XX":
#                 raise ValueError(
#                     "Invalid date: Month contains uncertainty, so day must also be uncertain."
#                 )


# Path: tests/util_support/test_date_disambiguator.py
import datetime
import pytest
from augur.util_support import date_disambiguator
from augur.util_support.date_disambiguator import DateDisambiguator
from freezegun import freeze_time

        ],
    )
    def test_range(self, date_str, expected_range):
        assert DateDisambiguator(date_str).range() == expected_range

    @pytest.mark.parametrize(
        "date_str, fmt",
        [
            ("2005-02-XX", "%Y-%m-%d"),
            ("2005/02/XX", "%Y/%m/%d"),
            ("2005-XX-02", "%Y-%d-%m"),
            ("200502XX", "%Y%m%d"),
        ],
    )
    def test_range_separators(self, date_str, fmt):
        assert DateDisambiguator(date_str, fmt=fmt).range() == (
            datetime.date(2005, 2, 1),
            datetime.date(2005, 2, 28),
        )

    @pytest.mark.parametrize(
        "date_str, expected_components",
        [
            ("2000-01-01", {"Y": "2000", "m": "01", "d": "01"}),
            ("2000-01-XX", {"Y": "2000", "m": "01", "d": "XX"}),
            ("2000-XX-XX", {"Y": "2000", "m": "XX", "d": "XX"}),
        ],
    )
    def test_uncertain_date_components(self, date_str, expected_components):
        assert (

            DateDisambiguator(date_str).uncertain_date_components == expected_components