Skip to content

Commit ff60173

Browse files
committed
Add attribute access for some moved constants back to fake_filesystem
- some if these had been accessed in user code, which caused a regression - add convenience function get_uid()/get_gid() - see #809
1 parent 1906fde commit ff60173

File tree

8 files changed

+95
-13
lines changed

8 files changed

+95
-13
lines changed

CHANGES.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,17 @@ The released versions correspond to PyPI releases.
33

44
## Unreleased
55

6+
### Changes
7+
* Made the user and group IDs accessible via dedicated ``get_uid`` and ``get_gid``
8+
functions (for symmetry to ``set_uid`` / ``set_gid``)
9+
610
### Fixes
711
* The test fixture is now included in the source distribution and installed
812
with the package.
13+
* Some public constants in `fake_filesystem` that had been moved to `helpers` are
14+
made accessible from there again (see [#809](../../issues/809)).
15+
* Add missing fake implementations for `os.getuid` and `os.getgid` (Posix only)
16+
917

1018
## [Version 5.2.1](https://pypi.python.org/pypi/pyfakefs/5.2.1) (2023-04-11)
1119
Support for latest Python 3.12 version.

docs/modules.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ Public Modules and Classes
77
Fake filesystem module
88
----------------------
99
.. automodule:: pyfakefs.helpers
10-
:members: set_uid, set_gid, reset_ids, is_root
10+
:members: get_uid, set_uid, get_gid, set_gid, reset_ids, is_root
1111

1212
Fake filesystem classes
1313
-----------------------

pyfakefs/fake_file.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,10 @@ def __init__(
159159
self._side_effect: Optional[Callable] = side_effect
160160
self.name: AnyStr = name # type: ignore[assignment]
161161
self.stat_result = FakeStatResult(
162-
filesystem.is_windows_fs, helpers.USER_ID, helpers.GROUP_ID, helpers.now()
162+
filesystem.is_windows_fs,
163+
helpers.get_uid(),
164+
helpers.get_gid(),
165+
helpers.now(),
163166
)
164167
if st_mode >> 12 == 0:
165168
st_mode |= S_IFREG

pyfakefs/fake_filesystem.py

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -159,10 +159,19 @@ class OSType(Enum):
159159
PatchMode = fake_io.PatchMode
160160

161161
is_root = helpers.is_root
162+
get_uid = helpers.get_uid
162163
set_uid = helpers.set_uid
164+
get_gid = helpers.get_gid
163165
set_gid = helpers.set_gid
164166
reset_ids = helpers.reset_ids
165167

168+
PERM_READ = helpers.PERM_READ
169+
PERM_WRITE = helpers.PERM_WRITE
170+
PERM_EXE = helpers.PERM_EXE
171+
PERM_DEF = helpers.PERM_DEF
172+
PERM_DEF_FILE = helpers.PERM_DEF_FILE
173+
PERM_ALL = helpers.PERM_ALL
174+
166175

167176
class FakeFilesystem:
168177
"""Provides the appearance of a real directory tree for unit testing.
@@ -735,7 +744,7 @@ def utime(
735744
times: Optional[Tuple[Union[int, float], Union[int, float]]] = None,
736745
*,
737746
ns: Optional[Tuple[int, int]] = None,
738-
follow_symlinks: bool = True
747+
follow_symlinks: bool = True,
739748
) -> None:
740749
"""Change the access and modified times of a file.
741750
@@ -1620,10 +1629,10 @@ def get_object_from_normpath(
16201629

16211630
@staticmethod
16221631
def _can_read(target, owner_can_read):
1623-
if target.st_uid == helpers.USER_ID:
1632+
if target.st_uid == helpers.get_uid():
16241633
if owner_can_read or target.st_mode & 0o400:
16251634
return True
1626-
if target.st_gid == helpers.GROUP_ID:
1635+
if target.st_gid == get_gid():
16271636
if target.st_mode & 0o040:
16281637
return True
16291638
return target.st_mode & 0o004
@@ -2914,5 +2923,14 @@ def _run_doctest() -> TestResults:
29142923
return doctest.testmod(pyfakefs.fake_filesystem)
29152924

29162925

2926+
def __getattr__(name):
2927+
# backwards compatibility for read access to globals moved to helpers
2928+
if name == "USER_ID":
2929+
return helpers.USER_ID
2930+
if name == "GROUP_ID":
2931+
return helpers.GROUP_ID
2932+
raise AttributeError(f"No attribute {name!r}.")
2933+
2934+
29172935
if __name__ == "__main__":
29182936
_run_doctest()

pyfakefs/fake_os.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@
6565
PERM_EXE,
6666
PERM_DEF,
6767
is_root,
68+
get_uid,
69+
get_gid,
6870
)
6971

7072
if TYPE_CHECKING:
@@ -134,6 +136,11 @@ def dir() -> List[str]:
134136
"removexattr",
135137
"setxattr",
136138
]
139+
if sys.platform != "win32":
140+
_dir += [
141+
"getgid",
142+
"getuid",
143+
]
137144
if use_scandir:
138145
_dir += ["scandir"]
139146
return _dir
@@ -1272,6 +1279,22 @@ def sendfile(self, fd_out: int, fd_in: int, offset: int, count: int) -> int:
12721279
return written
12731280
return 0
12741281

1282+
def getuid(self) -> int:
1283+
"""Returns the user id set in the fake filesystem.
1284+
If not changed using ``set_uid``, this is the uid of the real system.
1285+
"""
1286+
if self.filesystem.is_windows_fs:
1287+
raise NameError("name 'getuid' is not defined")
1288+
return get_uid()
1289+
1290+
def getgid(self) -> int:
1291+
"""Returns the group id set in the fake filesystem.
1292+
If not changed using ``set_gid``, this is the gid of the real system.
1293+
"""
1294+
if self.filesystem.is_windows_fs:
1295+
raise NameError("name 'getgid' is not defined")
1296+
return get_gid()
1297+
12751298
def fake_functions(self, original_functions) -> Set:
12761299
functions = set()
12771300
for fn in original_functions:

pyfakefs/helpers.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@
4444
GROUP_ID = os.getgid()
4545

4646

47+
def get_uid() -> int:
48+
"""Get the global user id. Same as ``os.getuid()``"""
49+
return USER_ID
50+
51+
4752
def set_uid(uid: int) -> None:
4853
"""Set the global user id. This is used as st_uid for new files
4954
and to differentiate between a normal user and the root user (uid 0).
@@ -56,6 +61,11 @@ def set_uid(uid: int) -> None:
5661
USER_ID = uid
5762

5863

64+
def get_gid() -> int:
65+
"""Get the global group id. Same as ``os.getgid()``"""
66+
return GROUP_ID
67+
68+
5969
def set_gid(gid: int) -> None:
6070
"""Set the global group id. This is only used to set st_gid for new files,
6171
no permission checks are performed.

pyfakefs/tests/fake_filesystem_shutil_test.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
from pathlib import Path
2626

2727
from pyfakefs import fake_filesystem_unittest
28-
from pyfakefs.helpers import USER_ID, set_uid, is_root
28+
from pyfakefs.helpers import get_uid, set_uid, is_root
2929
from pyfakefs.tests.test_utils import RealFsTestMixin
3030

3131
is_windows = sys.platform == "win32"
@@ -39,7 +39,7 @@ def __init__(self, methodName="runTest"):
3939
def setUp(self):
4040
RealFsTestMixin.setUp(self)
4141
self.cwd = os.getcwd()
42-
self.uid = USER_ID
42+
self.uid = get_uid()
4343
set_uid(1000)
4444
if not self.use_real_fs():
4545
self.setUpPyfakefs()

pyfakefs/tests/fake_os_test.py

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
import sys
2222
import unittest
2323

24-
from pyfakefs.helpers import IN_DOCKER, IS_PYPY, GROUP_ID, USER_ID
24+
from pyfakefs.helpers import IN_DOCKER, IS_PYPY, get_uid, get_gid
2525

2626
from pyfakefs import fake_filesystem, fake_os, fake_open, fake_file
2727
from pyfakefs.fake_filesystem import (
@@ -5403,6 +5403,26 @@ def chmod(self, path, mode):
54035403
else:
54045404
self.os.chmod(path, mode)
54055405

5406+
def test_getuid(self):
5407+
self.skip_real_fs() # won't change user in real fs
5408+
self.check_posix_only()
5409+
uid = self.os.getuid()
5410+
set_uid(uid + 10)
5411+
self.assertEqual(uid + 10, self.os.getuid())
5412+
self.assertEqual(uid + 10, get_uid())
5413+
set_uid(uid)
5414+
self.assertEqual(uid, self.os.getuid())
5415+
5416+
def test_getgid(self):
5417+
self.skip_real_fs() # won't change group in real fs
5418+
self.check_posix_only()
5419+
gid = self.os.getgid()
5420+
set_gid(gid + 10)
5421+
self.assertEqual(gid + 10, self.os.getgid())
5422+
self.assertEqual(gid + 10, get_gid())
5423+
set_gid(gid)
5424+
self.assertEqual(gid, self.os.getgid())
5425+
54065426
def test_listdir_unreadable_dir(self):
54075427
if not is_root():
54085428
self.assert_raises_os_error(errno.EACCES, self.os.listdir, self.dir_path)
@@ -5417,7 +5437,7 @@ def test_listdir_user_readable_dir(self):
54175437
def test_listdir_user_readable_dir_from_other_user(self):
54185438
self.skip_real_fs() # won't change user in real fs
54195439
self.check_posix_only()
5420-
user_id = USER_ID
5440+
user_id = get_uid()
54215441
set_uid(user_id + 1)
54225442
dir_path = self.make_path("dir1")
54235443
self.create_dir(dir_path, perm=0o600)
@@ -5431,7 +5451,7 @@ def test_listdir_user_readable_dir_from_other_user(self):
54315451

54325452
def test_listdir_group_readable_dir_from_other_user(self):
54335453
self.skip_real_fs() # won't change user in real fs
5434-
user_id = USER_ID
5454+
user_id = get_uid()
54355455
set_uid(user_id + 1)
54365456
dir_path = self.make_path("dir1")
54375457
self.create_dir(dir_path, perm=0o660)
@@ -5442,7 +5462,7 @@ def test_listdir_group_readable_dir_from_other_user(self):
54425462
def test_listdir_group_readable_dir_from_other_group(self):
54435463
self.skip_real_fs() # won't change user in real fs
54445464
self.check_posix_only()
5445-
group_id = GROUP_ID
5465+
group_id = self.os.getgid()
54465466
set_gid(group_id + 1)
54475467
dir_path = self.make_path("dir1")
54485468
self.create_dir(dir_path, perm=0o060)
@@ -5456,7 +5476,7 @@ def test_listdir_group_readable_dir_from_other_group(self):
54565476

54575477
def test_listdir_other_readable_dir_from_other_group(self):
54585478
self.skip_real_fs() # won't change user in real fs
5459-
group_id = GROUP_ID
5479+
group_id = get_gid()
54605480
set_gid(group_id + 1)
54615481
dir_path = self.make_path("dir1")
54625482
self.create_dir(dir_path, perm=0o004)
@@ -5489,7 +5509,7 @@ def test_remove_unreadable_dir(self):
54895509

54905510
def test_remove_unreadable_dir_from_other_user(self):
54915511
self.skip_real_fs() # won't change user in real fs
5492-
user_id = USER_ID
5512+
user_id = get_uid()
54935513
set_uid(user_id + 1)
54945514
dir_path = self.make_path("dir1")
54955515
self.create_dir(dir_path, perm=0o000)

0 commit comments

Comments
 (0)