Skip to content

Commit b126372

Browse files
committed
Add Sao Tome and Principe holidays with observed logic and subdivision support
1 parent 43656dc commit b126372

File tree

4 files changed

+195
-29
lines changed

4 files changed

+195
-29
lines changed

holidays/countries/sao_tome_and_principe.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ class SaoTomeAndPrincipe(
5858
supported_categories = (PUBLIC,)
5959
observed_label = tr("%s (observed)")
6060
supported_languages = ("en_US", "pt")
61-
start_year = 1975 # Independence year
61+
start_year = 2014
6262
observed_start_year = 2020 # Year when observed holidays began
6363

6464
def __init__(self, *args, **kwargs):
@@ -123,8 +123,7 @@ def _populate_public_holidays(self):
123123

124124
# Autonomy Day (April 29).
125125
# Príncipe gained autonomy in 1995.
126-
if self._year >= 1995:
127-
self._add_observed(self._add_holiday_apr_29(tr("Dia da Autonomia do Príncipe")))
126+
self._add_observed(self._add_holiday_apr_29(tr("Dia da Autonomia do Príncipe")))
128127

129128
# São Lourenço Day (August 15).
130129
self._add_observed(self._add_holiday_aug_15(tr("Dia de São Lourenço")))

holidays/locale/en_US/LC_MESSAGES/ST.po

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,15 @@ msgstr ""
1818
"Project-Id-Version: Holidays 0.71\n"
1919
"POT-Creation-Date: 2025-04-22 01:37+0530\n"
2020
"PO-Revision-Date: 2025-04-22 16:36+0530\n"
21-
"Last-Translator: \n"
21+
"Last-Translator: Devaraj K <[email protected]>\n"
2222
"Language-Team: Holidays Localization Team\n"
2323
"Language: pt\n"
2424
"MIME-Version: 1.0\n"
2525
"Content-Type: text/plain; charset=UTF-8\n"
2626
"Content-Transfer-Encoding: 8bit\n"
2727
"Generated-By: Lingva 5.0.6\n"
28-
"X-Source-Language: pt\n"
2928
"X-Generator: Poedit 3.5\n"
30-
31-
#, c-format
32-
msgid "%s (observado)"
33-
msgstr "%s (observed)"
29+
"X-Source-Language: pt\n"
3430

3531
#. National holidays (observed everywhere) New Year's Day.
3632
msgid "Ano Novo"
@@ -72,9 +68,18 @@ msgstr "Christmas Day"
7268
msgid "Descobrimento da Ilha do Príncipe"
7369
msgstr "Discovery of Príncipe Island"
7470

71+
#. Autonomy Day (April 29). Príncipe gained autonomy in 1995.
7572
msgid "Dia da Autonomia do Príncipe"
7673
msgstr "Autonomy Day"
7774

7875
#. São Lourenço Day (August 15).
7976
msgid "Dia de São Lourenço"
8077
msgstr "São Lourenço Day"
78+
79+
#, c-format
80+
msgid "%s (observed)"
81+
msgstr ""
82+
83+
#, c-format
84+
#~ msgid "%s (observado)"
85+
#~ msgstr "%s (observed)"

holidays/locale/pt/LC_MESSAGES/ST.po

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ msgstr ""
1818
"Project-Id-Version: Holidays 0.71\n"
1919
"POT-Creation-Date: 2025-04-22 01:37+0530\n"
2020
"PO-Revision-Date: 2025-04-22 01:37+0530\n"
21-
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
21+
"Last-Translator: Devaraj K <[email protected]>\n"
2222
"Language-Team: Holidays Localization Team\n"
2323
"Language: pt\n"
2424
"MIME-Version: 1.0\n"
@@ -71,6 +71,7 @@ msgstr ""
7171
msgid "Descobrimento da Ilha do Príncipe"
7272
msgstr ""
7373

74+
#. Autonomy Day (April 29). Príncipe gained autonomy in 1995.
7475
msgid "Dia da Autonomia do Príncipe"
7576
msgstr ""
7677

tests/countries/test_sao_tome_and_principe.py

Lines changed: 180 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
# Website: https://github.com/vacanza/holidays
1111
# License: MIT (see LICENSE file)
1212

13+
from datetime import date
1314
from unittest import TestCase
1415

1516
from holidays.countries.sao_tome_and_principe import SaoTomeAndPrincipe, ST, STP
@@ -19,8 +20,8 @@
1920
class TestSaoTome(CommonCountryTests, TestCase):
2021
@classmethod
2122
def setUpClass(cls):
22-
super().setUpClass(SaoTomeAndPrincipe, years=range(2014, 2026))
23-
cls.observed_holidays = SaoTomeAndPrincipe(years=range(2014, 2026), observed=True)
23+
super().setUpClass(SaoTomeAndPrincipe)
24+
cls.observed_holidays = SaoTomeAndPrincipe(observed=True)
2425

2526
def test_country_aliases(self):
2627
self.assertIsInstance(ST(), SaoTomeAndPrincipe)
@@ -97,6 +98,134 @@ def test_sao_tome_day(self):
9798
self.assertIn("2024-12-20", self.observed_holidays) # Dec 21 was Saturday
9899
self.assertIn("2025-12-22", self.observed_holidays) # Dec 21 was Sunday
99100

101+
def test_all_years_holidays(self):
102+
# 2014
103+
self.assertIn("2014-01-01", self.holidays) # New Year
104+
self.assertIn("2014-01-04", self.holidays) # Day of King Amador
105+
self.assertIn("2014-02-03", self.holidays) # Commemoration of the Batepá Massacre
106+
self.assertIn("2014-05-01", self.holidays) # Labour Day
107+
self.assertIn("2014-07-12", self.holidays) # Independence Day
108+
self.assertIn("2014-09-06", self.holidays) # Armed Forces' Day
109+
self.assertIn("2014-09-30", self.holidays) # Nationalization of the Roças
110+
self.assertIn("2014-12-25", self.holidays) # Christmas Day
111+
112+
# 2015
113+
self.assertIn("2015-01-01", self.holidays)
114+
self.assertIn("2015-01-04", self.holidays)
115+
self.assertIn("2015-02-03", self.holidays)
116+
self.assertIn("2015-05-01", self.holidays)
117+
self.assertIn("2015-07-12", self.holidays)
118+
self.assertIn("2015-09-06", self.holidays)
119+
self.assertIn("2015-09-30", self.holidays)
120+
self.assertIn("2015-12-25", self.holidays)
121+
122+
# 2016
123+
self.assertIn("2016-01-01", self.holidays)
124+
self.assertIn("2016-01-04", self.holidays)
125+
self.assertIn("2016-02-03", self.holidays)
126+
self.assertIn("2016-05-01", self.holidays)
127+
self.assertIn("2016-07-12", self.holidays)
128+
self.assertIn("2016-09-06", self.holidays)
129+
self.assertIn("2016-09-30", self.holidays)
130+
self.assertIn("2016-12-25", self.holidays)
131+
132+
# 2017
133+
self.assertIn("2017-01-01", self.holidays)
134+
self.assertIn("2017-01-04", self.holidays)
135+
self.assertIn("2017-02-03", self.holidays)
136+
self.assertIn("2017-05-01", self.holidays)
137+
self.assertIn("2017-07-12", self.holidays)
138+
self.assertIn("2017-09-06", self.holidays)
139+
self.assertIn("2017-09-30", self.holidays)
140+
self.assertIn("2017-12-25", self.holidays)
141+
142+
# 2018
143+
self.assertIn("2018-01-01", self.holidays)
144+
self.assertIn("2018-01-04", self.holidays)
145+
self.assertIn("2018-02-03", self.holidays)
146+
self.assertIn("2018-05-01", self.holidays)
147+
self.assertIn("2018-07-12", self.holidays)
148+
self.assertIn("2018-09-06", self.holidays)
149+
self.assertIn("2018-09-30", self.holidays)
150+
self.assertIn("2018-12-25", self.holidays)
151+
152+
# 2019
153+
self.assertIn("2019-01-01", self.holidays)
154+
self.assertIn("2019-01-04", self.holidays)
155+
self.assertIn("2019-02-03", self.holidays)
156+
self.assertIn("2019-05-01", self.holidays)
157+
self.assertIn("2019-07-12", self.holidays)
158+
self.assertIn("2019-09-06", self.holidays)
159+
self.assertIn("2019-09-30", self.holidays)
160+
self.assertIn("2019-12-21", self.holidays) # São Tomé Day (first year)
161+
self.assertIn("2019-12-25", self.holidays)
162+
163+
# 2020
164+
self.assertIn("2020-01-01", self.holidays)
165+
self.assertIn("2020-01-04", self.holidays)
166+
self.assertIn("2020-02-03", self.holidays)
167+
self.assertIn("2020-05-01", self.holidays)
168+
self.assertIn("2020-07-12", self.holidays)
169+
self.assertIn("2020-09-06", self.holidays)
170+
self.assertIn("2020-09-30", self.holidays)
171+
self.assertIn("2020-12-21", self.holidays) # São Tomé Day
172+
self.assertIn("2020-12-25", self.holidays)
173+
174+
# 2021
175+
self.assertIn("2021-01-01", self.holidays)
176+
self.assertIn("2021-01-04", self.holidays)
177+
self.assertIn("2021-02-03", self.holidays)
178+
self.assertIn("2021-05-01", self.holidays)
179+
self.assertIn("2021-07-12", self.holidays)
180+
self.assertIn("2021-09-06", self.holidays)
181+
self.assertIn("2021-09-30", self.holidays)
182+
self.assertIn("2021-12-21", self.holidays) # São Tomé Day
183+
self.assertIn("2021-12-25", self.holidays)
184+
185+
# 2022
186+
self.assertIn("2022-01-01", self.holidays)
187+
self.assertIn("2022-01-04", self.holidays)
188+
self.assertIn("2022-02-03", self.holidays)
189+
self.assertIn("2022-05-01", self.holidays)
190+
self.assertIn("2022-07-12", self.holidays)
191+
self.assertIn("2022-09-06", self.holidays)
192+
self.assertIn("2022-09-30", self.holidays)
193+
self.assertIn("2022-12-21", self.holidays) # São Tomé Day
194+
self.assertIn("2022-12-25", self.holidays)
195+
196+
# 2023
197+
self.assertIn("2023-01-01", self.holidays)
198+
self.assertIn("2023-01-04", self.holidays)
199+
self.assertIn("2023-02-03", self.holidays)
200+
self.assertIn("2023-05-01", self.holidays)
201+
self.assertIn("2023-07-12", self.holidays)
202+
self.assertIn("2023-09-06", self.holidays)
203+
self.assertIn("2023-09-30", self.holidays)
204+
self.assertIn("2023-12-21", self.holidays) # São Tomé Day
205+
self.assertIn("2023-12-25", self.holidays)
206+
207+
# 2024
208+
self.assertIn("2024-01-01", self.holidays)
209+
self.assertIn("2024-01-04", self.holidays)
210+
self.assertIn("2024-02-03", self.holidays)
211+
self.assertIn("2024-05-01", self.holidays)
212+
self.assertIn("2024-07-12", self.holidays)
213+
self.assertIn("2024-09-06", self.holidays)
214+
self.assertIn("2024-09-30", self.holidays)
215+
self.assertIn("2024-12-21", self.holidays) # São Tomé Day
216+
self.assertIn("2024-12-25", self.holidays)
217+
218+
# 2025
219+
self.assertIn("2025-01-01", self.holidays)
220+
self.assertIn("2025-01-04", self.holidays)
221+
self.assertIn("2025-02-03", self.holidays)
222+
self.assertIn("2025-05-01", self.holidays)
223+
self.assertIn("2025-07-12", self.holidays)
224+
self.assertIn("2025-09-06", self.holidays)
225+
self.assertIn("2025-09-30", self.holidays)
226+
self.assertIn("2025-12-21", self.holidays) # São Tomé Day
227+
self.assertIn("2025-12-25", self.holidays)
228+
100229
def test_principe_specific_holidays(self):
101230
# Test Príncipe-specific holidays
102231
principe_dates = {
@@ -131,17 +260,6 @@ def test_localization(self):
131260
self.assertEqual(en_holidays["2025-01-03"], "Day of King Amador (observed)")
132261
self.assertEqual(en_holidays["2025-12-25"], "Christmas Day")
133262

134-
def test_autonomy_day_history(self):
135-
"""Test Autonomy Day only appears from 1995 onwards in Príncipe."""
136-
# Before 1995 - shouldn't exist
137-
st_pr_pre_1995 = SaoTomeAndPrincipe(subdiv="PR", years=1994)
138-
self.assertNotIn("1994-04-29", st_pr_pre_1995)
139-
140-
# From 1995 onwards - should exist
141-
st_pr_post_1995 = SaoTomeAndPrincipe(subdiv="PR", years=1995)
142-
self.assertIn("1995-04-29", st_pr_post_1995)
143-
self.assertEqual(st_pr_post_1995["1995-04-29"], "Dia da Autonomia do Príncipe")
144-
145263
def test_observed_suffix_translation(self):
146264
"""Test observed suffix is correctly set based on language."""
147265
st_en = SaoTomeAndPrincipe(language="en_US")
@@ -155,11 +273,54 @@ def test_observed_suffix_translation(self):
155273

156274
def test_no_observed_holidays_before_2020(self):
157275
"""Test that no observed holidays exist before 2020."""
158-
for year in range(1975, 2020): # Before observed_start_year (2020)
276+
for year in range(2014, 2020): # Before observed_start_year (2020)
159277
holidays = SaoTomeAndPrincipe(years=year, observed=True)
160278

161-
# Check New Year's Day (Jan 1) never has an observed date before 2020
162-
jan1 = f"{year}-01-01"
163-
if jan1 in holidays:
164-
jan2 = f"{year}-01-02"
165-
self.assertNotIn(jan2, holidays) # No observed date should exist
279+
# Check New Year's Day (Jan 1) never has an observed date before 2020
280+
jan1 = f"{year}-01-01"
281+
if jan1 in holidays:
282+
jan2 = f"{year}-01-02"
283+
self.assertNotIn(jan2, holidays) # No observed date should exist
284+
285+
def test_invalid_language_fallback(self):
286+
st = ST(language="xx", years=2024)
287+
# Should fallback to default (Portuguese)
288+
assert st[date(2024, 1, 1)] == "Ano Novo"
289+
290+
def test_populate_holidays_and_observed_logic(self):
291+
"""Tests holiday population, observed logic, and pre-2014 early return."""
292+
from holidays.countries.sao_tome_and_principe import SaoTomeAndPrincipe
293+
294+
# Test 1: Directly test pre-2014 early return
295+
st = SaoTomeAndPrincipe.__new__(SaoTomeAndPrincipe)
296+
st._year = 2013
297+
result = st._populate_public_holidays()
298+
self.assertIsNone(result)
299+
300+
# Test 2: Normal operation with observed holidays
301+
st_normal = SaoTomeAndPrincipe(years=2020, observed=True)
302+
self.assertIn(date(2020, 1, 1), st_normal) # New Year's
303+
self.assertIn(date(2020, 1, 3), st_normal) # Observed holiday
304+
305+
# Test 3: Principe-specific holidays
306+
st_pr = SaoTomeAndPrincipe(years=2020, subdiv="PR")
307+
self.assertIn(date(2020, 1, 17), st_pr) # Principe Discovery Day
308+
309+
# Test 4: São Tomé Day (post-2019)
310+
st_2019 = SaoTomeAndPrincipe(years=2019)
311+
self.assertIn(date(2019, 12, 21), st_2019)
312+
313+
def test_observed_suffix_and_principe_branch_logic(self):
314+
"""Tests localization of observed suffix and non-Principe subdivision exclusion."""
315+
from holidays.countries.sao_tome_and_principe import SaoTomeAndPrincipe
316+
317+
# Test observed_suffix localization
318+
st_en = SaoTomeAndPrincipe(language="en_US")
319+
self.assertEqual(st_en.observed_suffix, "%s (observed)")
320+
321+
st_pt = SaoTomeAndPrincipe(language="pt")
322+
self.assertEqual(st_pt.observed_suffix, "%s (observado)")
323+
324+
# Test that non-PR subdivisions do not get Principe holiday
325+
st_no_pr = SaoTomeAndPrincipe(years=2020, subdiv="01") # Not PR
326+
self.assertNotIn("2020-01-17", st_no_pr)

0 commit comments

Comments
 (0)