@@ -2489,6 +2489,87 @@ def my_mkdir(path, mode=0o777):
24892489 self .assertNotIn (str (p12 ), concurrently_created )
24902490 self .assertTrue (p .exists ())
24912491
2492+ @unittest .skipIf (
2493+ is_emscripten or is_wasi ,
2494+ "umask is not implemented on Emscripten/WASI."
2495+ )
2496+ def test_mkdir_parents_umask (self ):
2497+ # Test that parent directories respect umask when parent_mode is not set
2498+ p = self .cls (self .base , 'umasktest' , 'child' )
2499+ self .assertFalse (p .exists ())
2500+ if os .name != 'nt' :
2501+ old_mask = os .umask (0o002 )
2502+ try :
2503+ p .mkdir (0o755 , parents = True )
2504+ self .assertTrue (p .exists ())
2505+ # Leaf directory gets the specified mode
2506+ self .assertEqual (stat .S_IMODE (p .stat ().st_mode ), 0o755 )
2507+ # Parent directory respects umask (0o777 & ~0o002 = 0o775)
2508+ self .assertEqual (stat .S_IMODE (p .parent .stat ().st_mode ), 0o775 )
2509+ finally :
2510+ os .umask (old_mask )
2511+
2512+ def test_mkdir_with_parent_mode (self ):
2513+ # Test the parent_mode parameter
2514+ p = self .cls (self .base , 'newdirPM' , 'subdirPM' )
2515+ self .assertFalse (p .exists ())
2516+ if os .name != 'nt' :
2517+ # Specify different modes for parent and leaf directories
2518+ p .mkdir (0o755 , parents = True , parent_mode = 0o750 )
2519+ self .assertTrue (p .exists ())
2520+ self .assertTrue (p .is_dir ())
2521+ # Leaf directory gets the mode parameter
2522+ self .assertEqual (stat .S_IMODE (p .stat ().st_mode ), 0o755 )
2523+ # Parent directory gets the parent_mode parameter
2524+ self .assertEqual (stat .S_IMODE (p .parent .stat ().st_mode ), 0o750 )
2525+
2526+ def test_mkdir_parent_mode_deep_hierarchy (self ):
2527+ # Test parent_mode with deep directory hierarchy
2528+ p = self .cls (self .base , 'level1PM' , 'level2PM' , 'level3PM' )
2529+ self .assertFalse (p .exists ())
2530+ if os .name != 'nt' :
2531+ p .mkdir (0o755 , parents = True , parent_mode = 0o700 )
2532+ self .assertTrue (p .exists ())
2533+ # Check that all parent directories have parent_mode
2534+ level1 = self .cls (self .base , 'level1PM' )
2535+ level2 = level1 / 'level2PM'
2536+ self .assertEqual (stat .S_IMODE (level1 .stat ().st_mode ), 0o700 )
2537+ self .assertEqual (stat .S_IMODE (level2 .stat ().st_mode ), 0o700 )
2538+ # Leaf directory has the regular mode
2539+ self .assertEqual (stat .S_IMODE (p .stat ().st_mode ), 0o755 )
2540+
2541+ @unittest .skipIf (
2542+ is_emscripten or is_wasi ,
2543+ "umask is not implemented on Emscripten/WASI."
2544+ )
2545+ def test_mkdir_parent_mode_overrides_umask (self ):
2546+ # Test that parent_mode overrides umask for parent directories
2547+ p = self .cls (self .base , 'overridetest' , 'child' )
2548+ self .assertFalse (p .exists ())
2549+ if os .name != 'nt' :
2550+ old_mask = os .umask (0o022 ) # Restrictive umask
2551+ try :
2552+ # parent_mode should override umask for parents
2553+ p .mkdir (0o755 , parents = True , parent_mode = 0o700 )
2554+ self .assertTrue (p .exists ())
2555+ # Leaf directory gets the specified mode
2556+ self .assertEqual (stat .S_IMODE (p .stat ().st_mode ), 0o755 )
2557+ # Parent directory gets parent_mode, not affected by umask
2558+ self .assertEqual (stat .S_IMODE (p .parent .stat ().st_mode ), 0o700 )
2559+ finally :
2560+ os .umask (old_mask )
2561+
2562+ def test_mkdir_parent_mode_same_as_mode (self ):
2563+ # Test setting parent_mode same as mode
2564+ p = self .cls (self .base , 'samedirPM' , 'subdirPM' )
2565+ self .assertFalse (p .exists ())
2566+ if os .name != 'nt' :
2567+ p .mkdir (0o705 , parents = True , parent_mode = 0o705 )
2568+ self .assertTrue (p .exists ())
2569+ # Both directories should have the same mode
2570+ self .assertEqual (stat .S_IMODE (p .stat ().st_mode ), 0o705 )
2571+ self .assertEqual (stat .S_IMODE (p .parent .stat ().st_mode ), 0o705 )
2572+
24922573 @needs_symlinks
24932574 def test_symlink_to (self ):
24942575 P = self .cls (self .base )
0 commit comments