Repository: peopledoc/workalendar
Pull request #603 (2020-12-11 21:20:25)

Use pathlib.Path instead of os.path.*
- [x] Tests with a significant number of years to be tested for your calendar.
- [x] Changelog amended with a mention describing your changes. **Note** *Please do NOT change the version number here. It's the project maintainers' duty.*



Patch:
diff --git a/Changelog.md b/Changelog.md
index e359172..e20c8bc 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -2,7 +2,7 @@
 
 ## master (unreleased)
 
-Nothing here yet.
+- Replace `os.path.*` calls with `pathlib.Path`
 
 ## v14.1.0 (2020-12-10)
 
diff --git a/workalendar/core.py b/workalendar/core.py
index 21ace29..5e8b979 100644
--- a/workalendar/core.py
+++ b/workalendar/core.py
@@ -2,11 +2,10 @@
 Working day tools
 """
 from copy import copy
-import os
-from os.path import isdir
 import warnings
 from calendar import monthrange
 from datetime import date, timedelta, datetime
+from pathlib import Path
 
 from calverter import Calverter
 from dateutil import easter
@@ -874,14 +873,16 @@ class CoreCalendar:
             raise ICalExportTargetPathError(
                 "Incorrect target path. It must not be empty")
 
-        if isdir(target_path):
+        target_path = Path(target_path)
+
+        if target_path.is_dir():
             raise ICalExportTargetPathError(
                 "Incorrect target path. It must not be a directory"
             )
 
         ical_extensions = ['.ical', '.ics', '.ifb', '.icalendar']
-        if os.path.splitext(target_path)[1] not in ical_extensions:
-            target_path += '.ics'
+        if target_path.suffix not in ical_extensions:
+            target_path = target_path.with_name(target_path.name + '.ics')
         return target_path
 
     def export_to_ical(self, period=[2000, 2030], target_path=None):
@@ -894,7 +895,7 @@ class CoreCalendar:
             start and end year (inclusive) of calendar
             Default is [2000, 2030]
 
-        target_path: str
+        target_path: str or pathlib.Path
             the name or path of the exported file. If this argument is missing,
             the function will return the ical content.
 
@@ -937,7 +938,7 @@ class CoreCalendar:
 
         if target_path:
             # save iCal file
-            with open(target_path, 'w+') as export_file:
+            with target_path.open('w+') as export_file:
                 export_file.write(ics)
             return
 


Test patch:
diff --git a/workalendar/tests/__init__.py b/workalendar/tests/__init__.py
index 3d95165..192e01a 100644
--- a/workalendar/tests/__init__.py
+++ b/workalendar/tests/__init__.py
@@ -1,8 +1,7 @@
 import tempfile
-import os
-from os.path import join
 import warnings
 from datetime import date
+from pathlib import Path
 from unittest import TestCase
 
 from freezegun import freeze_time
@@ -55,20 +54,21 @@ class GenericCalendarTest(CoreCalendarTest):
 
         holidays = self.cal.holidays(2019) + self.cal.holidays(2020)
 
-        temp_dir = join(tempfile.gettempdir(), "failed_ical_tests")
-        os.makedirs(temp_dir, exist_ok=True)
+        temp_dir = Path(tempfile.gettempdir()) / "failed_ical_tests"
+        temp_dir.mkdir(parents=True, exist_ok=True)
         _, test_file_name = tempfile.mkstemp(
             prefix="%s_" % self.cal_class.__name__,
             suffix=".ics",
             dir=temp_dir,
         )
+        test_path = Path(test_file_name)
 
         self.cal.export_to_ical(
             period=[2019, 2020],
-            target_path=test_file_name,
+            target_path=test_path,
         )
         # A standard iCal extension should have been added automatically:
-        with open(test_file_name) as ics_file:
+        with test_path.open() as ics_file:
             # check header
             assert ics_file.readline() == 'BEGIN:VCALENDAR\n'
             assert ics_file.readline() == 'VERSION:2.0\n'
@@ -107,15 +107,14 @@ class GenericCalendarTest(CoreCalendarTest):
             # Regenerate the file
             self.cal.export_to_ical(
                 period=[2019, 2020],
-                target_path=test_file_name,
+                target_path=test_path,
             )
             # Not providing any target => returns the value as a string
             var_contents = self.cal.export_to_ical(period=[2019, 2020])
 
-        with open(test_file_name) as fd:
-            file_contents = fd.read()
+        file_contents = test_path.read_text()
 
         assert file_contents == var_contents
 
         # Remove the .ics file if this test passes
-        os.remove(test_file_name)
+        test_path.unlink()
diff --git a/workalendar/tests/test_ical_export.py b/workalendar/tests/test_ical_export.py
index 2e3f3a0..9dde45d 100644
--- a/workalendar/tests/test_ical_export.py
+++ b/workalendar/tests/test_ical_export.py
@@ -1,6 +1,5 @@
 import tempfile
-import os
-from os.path import join
+from pathlib import Path
 
 from ..core import Calendar
 from ..exceptions import ICalExportRangeError, ICalExportTargetPathError
@@ -111,31 +110,40 @@ class ICalExportTargetPath(CoreCalendarTest):
             self.cal._get_ical_target_path(None)
 
     def test_target_is_directory(self):
-        temp_dir = join(tempfile.gettempdir(), "failed_ical_tests")
-        os.makedirs(temp_dir, exist_ok=True)
+        temp_dir = Path(tempfile.gettempdir()) / "failed_ical_tests"
+        temp_dir.mkdir(parents=True, exist_ok=True)
 
         with self.assertRaises(ICalExportTargetPathError):
             self.cal._get_ical_target_path(temp_dir)
 
     def test_no_extension(self):
         # Relative paths
-        self.assertEqual(self.cal._get_ical_target_path("a"), "a.ics")
-        self.assertEqual(self.cal._get_ical_target_path("a/b"), "a/b.ics")
+        self.assertEqual(self.cal._get_ical_target_path("a"), Path("a.ics"))
+        self.assertEqual(
+            self.cal._get_ical_target_path("a/b"),
+            Path("a/b.ics")
+        )
         # Absolute path
         self.assertEqual(
             self.cal._get_ical_target_path("/path/to/a"),
-            "/path/to/a.ics"
+            Path("/path/to/a.ics")
         )
 
     def test_known_extensions(self):
         for ext in ('ical', 'ics', 'ifb', 'icalendar'):
-            filename = f"a.{ext}"
+            filename = Path(f"a.{ext}")
             self.assertEqual(
                 self.cal._get_ical_target_path(filename),
                 filename
             )
 
     def test_added_extensions(self):
-        self.assertEqual(self.cal._get_ical_target_path('a.'), 'a..ics')
-        self.assertEqual(self.cal._get_ical_target_path('a.txt'), 'a.txt.ics')
-        self.assertEqual(self.cal._get_ical_target_path('.test'), '.test.ics')
+        self.assertEqual(self.cal._get_ical_target_path('a.'), Path('a..ics'))
+        self.assertEqual(
+            self.cal._get_ical_target_path('a.txt'),
+            Path('a.txt.ics')
+        )
+        self.assertEqual(
+            self.cal._get_ical_target_path('.test'),
+            Path('.test.ics')
+        )