Repository: vacanza/holidays
Pull request #2122 (2024-11-09 18:55:04)

Update helpers::_normalize_arguments, add helpers tests
<!--
  Thanks for contributing to holidays!
-->

## Proposed change

<!--
  Describe the big picture of your changes.
  Don't forget to link your PR to an existing issue if any.
-->

Update helpers::_normalize_arguments, add helpers tests

## Type of change

<!--
  Type of change you want to introduce. Please, check one (1) box only!
  If your PR requires multiple boxes to be checked, most likely it needs to
  be split into multiple PRs.
-->

- [ ] New country/market holidays support (thank you!)
- [ ] Supported country/market holidays update (calendar discrepancy fix, localization)
- [x] Existing code/documentation/test/process quality improvement (best practice, cleanup, refactoring, optimization)
- [ ] Dependency update (version deprecation/pin/upgrade)
- [ ] Bugfix (non-breaking change which fixes an issue)
- [ ] Breaking change (a code change causing existing functionality to break)
- [ ] New feature (new `holidays` functionality in general)

## Checklist

<!--
  Put an `x` in the boxes that apply. You can change them after PR is created.
-->

- [x] I've followed the [contributing guidelines][contributing-guidelines]
- [x] I've successfully run `make check`, all checks and tests are green

<!--
  Thanks again for your contribution!
-->

[contributing-guidelines]: https://github.com/vacanza/holidays/blob/dev/CONTRIBUTING.rst
[docs]: https://github.com/vacanza/holidays/tree/dev/docs/source


sonarcloud[bot]: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=vacanza_python-holidays&pullRequest=2122) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=vacanza_python-holidays&pullRequest=2122&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=vacanza_python-holidays&pullRequest=2122&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=vacanza_python-holidays&pullRequest=2122&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=vacanza_python-holidays&pullRequest=2122&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=vacanza_python-holidays&pullRequest=2122&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarCloud](https://sonarcloud.io/dashboard?id=vacanza_python-holidays&pullRequest=2122)


codecov[bot]: ## [Codecov](https://app.codecov.io/gh/vacanza/holidays/pull/2122?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=vacanza) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 100.00%. Comparing base [(`a4fcbc7`)](https://app.codecov.io/gh/vacanza/holidays/commit/a4fcbc720a5fb458ee790b7cc1c56c329937f539?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=vacanza) to head [(`9bd7c98`)](https://app.codecov.io/gh/vacanza/holidays/commit/9bd7c98a56fcff7d520a1c344cdc343d4a84b764?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=vacanza).

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff            @@
##               dev     #2122   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files          192       192           
  Lines        11590     11590           
  Branches      1747      1747           
=========================================
  Hits         11590     11590           
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/vacanza/holidays/pull/2122?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=vacanza).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=vacanza).


Patch:
diff --git a/holidays/helpers.py b/holidays/helpers.py
index 0eb22d6f..df0143ca 100644
--- a/holidays/helpers.py
+++ b/holidays/helpers.py
@@ -27,13 +27,13 @@ def _normalize_arguments(cls, value):
     if value is None:
         return set()
 
-    if isinstance(value, cls):
-        return {value}
+    if isinstance(value, str):
+        return {cls(value)}
 
     try:
-        return {v if isinstance(v, cls) else cls(v) for v in value}
+        return {cls(v) for v in value}
     except TypeError:  # non-iterable
-        return {value if isinstance(value, cls) else cls(value)}
+        return {cls(value)}
 
 
 def _normalize_tuple(value):


Test patch:
diff --git a/tests/common.py b/tests/common.py
index 4f89115c..f70e4f8d 100644
--- a/tests/common.py
+++ b/tests/common.py
@@ -302,7 +302,7 @@ class TestCase:
     def _assertLocalizedHolidays(self, localized_holidays, language=None):  # noqa: N802
         """Helper: assert localized holidays match expected names."""
         instance = self.test_class(
-            years=int(localized_holidays[0][0].split("-")[0]),
+            years=localized_holidays[0][0].split("-")[0],
             language=language,
             categories=self.test_class.supported_categories,
         )
diff --git a/tests/test_helpers.py b/tests/test_helpers.py
new file mode 100644
index 00000000..f528733c
--- /dev/null
+++ b/tests/test_helpers.py
@@ -0,0 +1,65 @@
+#  holidays
+#  --------
+#  A fast, efficient Python library for generating country, province and state
+#  specific sets of holidays on the fly. It aims to make determining whether a
+#  specific date is a holiday as fast and flexible as possible.
+#
+#  Authors: Vacanza Team and individual contributors (see AUTHORS file)
+#           dr-prodigy <dr.prodigy.github@gmail.com> (c) 2017-2023
+#           ryanss <ryanssdev@icloud.com> (c) 2014-2017
+#  Website: https://github.com/vacanza/holidays
+#  License: MIT (see LICENSE file)
+
+from unittest import TestCase
+
+from holidays.helpers import _normalize_arguments, _normalize_tuple
+
+
+class TestHelpers(TestCase):
+    def test_normalize_arguments(self):
+        empty_set = set()
+        input_expected_pairs = (
+            ((int, []), empty_set),
+            ((int, {}), empty_set),
+            ((int, None), empty_set),
+            ((str, []), empty_set),
+            ((str, {}), empty_set),
+            ((str, None), empty_set),
+            ((int, "1"), {1}),
+            ((int, "12"), {12}),
+            ((int, "121"), {121}),
+            ((int, ["1", "1"]), {1}),
+            ((int, ["1", "2"]), {1, 2}),
+            ((int, [1, 1]), {1}),
+            ((int, [1, 2]), {1, 2}),
+            ((int, [1]), {1}),
+            ((int, {1}), {1}),
+            ((int, 0), {0}),
+            ((int, 1.0), {1.0}),
+            ((int, 1), {1}),
+            ((str, "1"), {"1"}),
+            ((str, ("test1", "TEST1")), {"test1", "TEST1"}),
+            ((str, ("test1", "test1")), {"test1"}),
+            ((str, ("test1", "test2")), {"test1", "test2"}),
+            ((str, ["1", "2"]), {"1", "2"}),
+            ((str, [1, 2]), {"1", "2"}),
+            ((str, [1]), {"1"}),
+            ((str, {1: "2"}), {"1"}),
+            ((str, {1: 2}), {"1"}),
+            ((str, {1}), {"1"}),
+            ((str, 1.0), {"1.0"}),
+            ((str, 1), {"1"}),
+        )
+
+        for input, expected in input_expected_pairs:
+            self.assertEqual(_normalize_arguments(*input), expected)
+
+    def test_normalize_tuple(self):
+        input_expected_pairs = (
+            ((), ()),
+            ((1,), ((1,),)),
+            ((1, 2), ((1, 2),)),
+            (((1, 1), (2, 2)), ((1, 1), (2, 2))),
+        )
+        for input, expected in input_expected_pairs:
+            self.assertEqual(_normalize_tuple(input), expected)