11import io
22import logging
33import os
4+ import stat
45import sys
56import textwrap
67from unittest import mock
78
89import pytest
9- import sh
1010
1111import dotenv
1212
13+ if sys .platform != "win32" :
14+ import sh
15+
1316
1417def test_set_key_no_file (tmp_path ):
1518 nx_path = tmp_path / "nx"
@@ -62,15 +65,25 @@ def test_set_key_encoding(dotenv_path):
6265
6366
6467@pytest .mark .skipif (
65- os .geteuid () == 0 , reason = "Root user can access files even with 000 permissions."
68+ sys .platform != "win32" and os .geteuid () == 0 ,
69+ reason = "Root user can access files even with 000 permissions." ,
6670)
6771def test_set_key_permission_error (dotenv_path ):
68- dotenv_path .chmod (0o000 )
72+ if sys .platform == "win32" :
73+ # On Windows, make file read-only
74+ dotenv_path .chmod (stat .S_IREAD )
75+ else :
76+ # On Unix, remove all permissions
77+ dotenv_path .chmod (0o000 )
6978
7079 with pytest .raises (PermissionError ):
7180 dotenv .set_key (dotenv_path , "a" , "b" )
7281
73- dotenv_path .chmod (0o600 )
82+ # Restore permissions
83+ if sys .platform == "win32" :
84+ dotenv_path .chmod (stat .S_IWRITE | stat .S_IREAD )
85+ else :
86+ dotenv_path .chmod (0o600 )
7487 assert dotenv_path .read_text () == ""
7588
7689
@@ -170,16 +183,6 @@ def test_unset_encoding(dotenv_path):
170183 assert dotenv_path .read_text (encoding = encoding ) == ""
171184
172185
173- @pytest .mark .skipif (
174- os .geteuid () == 0 , reason = "Root user can access files even with 000 permissions."
175- )
176- def test_set_key_unauthorized_file (dotenv_path ):
177- dotenv_path .chmod (0o000 )
178-
179- with pytest .raises (PermissionError ):
180- dotenv .set_key (dotenv_path , "a" , "x" )
181-
182-
183186def test_unset_non_existent_file (tmp_path ):
184187 nx_path = tmp_path / "nx"
185188 logger = logging .getLogger ("dotenv.main" )
@@ -241,6 +244,9 @@ def test_find_dotenv_found(tmp_path):
241244 assert result == str (dotenv_path )
242245
243246
247+ @pytest .mark .skipif (
248+ sys .platform == "win32" , reason = "This test assumes case-sensitive variable names"
249+ )
244250@mock .patch .dict (os .environ , {}, clear = True )
245251def test_load_dotenv_existing_file (dotenv_path ):
246252 dotenv_path .write_text ("a=b" )
@@ -312,6 +318,9 @@ def test_load_dotenv_disabled_notification(dotenv_path, flag_value):
312318 )
313319
314320
321+ @pytest .mark .skipif (
322+ sys .platform == "win32" , reason = "This test assumes case-sensitive variable names"
323+ )
315324@pytest .mark .parametrize (
316325 "flag_value" ,
317326 [
@@ -395,6 +404,9 @@ def test_load_dotenv_no_file_verbose():
395404 )
396405
397406
407+ @pytest .mark .skipif (
408+ sys .platform == "win32" , reason = "This test assumes case-sensitive variable names"
409+ )
398410@mock .patch .dict (os .environ , {"a" : "c" }, clear = True )
399411def test_load_dotenv_existing_variable_no_override (dotenv_path ):
400412 dotenv_path .write_text ("a=b" )
@@ -405,6 +417,9 @@ def test_load_dotenv_existing_variable_no_override(dotenv_path):
405417 assert os .environ == {"a" : "c" }
406418
407419
420+ @pytest .mark .skipif (
421+ sys .platform == "win32" , reason = "This test assumes case-sensitive variable names"
422+ )
408423@mock .patch .dict (os .environ , {"a" : "c" }, clear = True )
409424def test_load_dotenv_existing_variable_override (dotenv_path ):
410425 dotenv_path .write_text ("a=b" )
@@ -415,6 +430,9 @@ def test_load_dotenv_existing_variable_override(dotenv_path):
415430 assert os .environ == {"a" : "b" }
416431
417432
433+ @pytest .mark .skipif (
434+ sys .platform == "win32" , reason = "This test assumes case-sensitive variable names"
435+ )
418436@mock .patch .dict (os .environ , {"a" : "c" }, clear = True )
419437def test_load_dotenv_redefine_var_used_in_file_no_override (dotenv_path ):
420438 dotenv_path .write_text ('a=b\n d="${a}"' )
@@ -425,6 +443,9 @@ def test_load_dotenv_redefine_var_used_in_file_no_override(dotenv_path):
425443 assert os .environ == {"a" : "c" , "d" : "c" }
426444
427445
446+ @pytest .mark .skipif (
447+ sys .platform == "win32" , reason = "This test assumes case-sensitive variable names"
448+ )
428449@mock .patch .dict (os .environ , {"a" : "c" }, clear = True )
429450def test_load_dotenv_redefine_var_used_in_file_with_override (dotenv_path ):
430451 dotenv_path .write_text ('a=b\n d="${a}"' )
@@ -435,6 +456,9 @@ def test_load_dotenv_redefine_var_used_in_file_with_override(dotenv_path):
435456 assert os .environ == {"a" : "b" , "d" : "b" }
436457
437458
459+ @pytest .mark .skipif (
460+ sys .platform == "win32" , reason = "This test assumes case-sensitive variable names"
461+ )
438462@mock .patch .dict (os .environ , {}, clear = True )
439463def test_load_dotenv_string_io_utf_8 ():
440464 stream = io .StringIO ("a=à" )
@@ -445,6 +469,9 @@ def test_load_dotenv_string_io_utf_8():
445469 assert os .environ == {"a" : "à" }
446470
447471
472+ @pytest .mark .skipif (
473+ sys .platform == "win32" , reason = "This test assumes case-sensitive variable names"
474+ )
448475@mock .patch .dict (os .environ , {}, clear = True )
449476def test_load_dotenv_file_stream (dotenv_path ):
450477 dotenv_path .write_text ("a=b" )
@@ -456,6 +483,7 @@ def test_load_dotenv_file_stream(dotenv_path):
456483 assert os .environ == {"a" : "b" }
457484
458485
486+ @pytest .mark .skipif (sys .platform == "win32" , reason = "sh module doesn't support Windows" )
459487def test_load_dotenv_in_current_dir (tmp_path ):
460488 dotenv_path = tmp_path / ".env"
461489 dotenv_path .write_bytes (b"a=b" )
@@ -484,6 +512,9 @@ def test_dotenv_values_file(dotenv_path):
484512 assert result == {"a" : "b" }
485513
486514
515+ @pytest .mark .skipif (
516+ sys .platform == "win32" , reason = "This test assumes case-sensitive variable names"
517+ )
487518@pytest .mark .parametrize (
488519 "env,string,interpolate,expected" ,
489520 [
0 commit comments