对os.stat(myfile).st_mode更好的assertEqual()

时间:2015-09-16 11:10:23

标签: python chmod readability stat

我有一个代码检查文件的st_mode:

self.assertEqual(16877, os.stat(my_directory).st_mode)

只有老派unix专家能够流畅地解读整数值16877

是否有更可读的方法来检查这个值?

4 个答案:

答案 0 :(得分:6)

您可以使用已定义的constats。它们可以在statdocs)中找到。他们是:

stat.S_IRUSR获取所有者的读取权限,

stat.S_IWUSR用于所有者写入权限,

所有者执行权限

stat.S_IXUSR

stat.S_IRGRP获取群组阅读权限,

stat.S_IWGRP用于群组写入权限,

stat.S_IXGRP用于群组执行权限,

stat.S_IROTH获得其他人的读取权限,

stat.S_IWOTH其他人写入权限,

stat.S_IXOTH为其他人执行权限,

stat.S_IFDIR目录。

可以使用按位或|组合它们。然后你的代码看起来像:

import stat
import os

permissions = (stat.S_IFDIR | 
               stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR |
               stat.S_IRGRP | stat.S_IXGRP |
               stat.S_IROTH | stat.S_IXOTH)
self.assertEqual(permissions, os.stat(my_directory).st_mode)

答案 1 :(得分:3)

Herest_mode手册中提供了有关stat的一些信息,引用如下。

       S_IFMT     0170000   bit mask for the file type bit field
       S_IFSOCK   0140000   socket
       S_IFLNK    0120000   symbolic link
       S_IFREG    0100000   regular file
       S_IFBLK    0060000   block device
       S_IFDIR    0040000   directory
       S_IFCHR    0020000   character device
       S_IFIFO    0010000   FIFO
       S_ISUID      04000   set-user-ID bit
       S_ISGID      02000   set-group-ID bit (see below)
       S_ISVTX      01000   sticky bit (see below)
       S_IRWXU      00700   owner has read, write, and execute permission
       S_IRUSR      00400   owner has read permission
       S_IWUSR      00200   owner has write permission
       S_IXUSR      00100   owner has execute permission
       S_IRWXG      00070   group has read, write, and execute permission
       S_IRGRP      00040   group has read permission
       S_IWGRP      00020   group has write permission
       S_IXGRP      00010   group has execute permission
       S_IRWXO      00007   others (not in group) have read, write, and
                            execute permission
       S_IROTH      00004   others have read permission
       S_IWOTH      00002   others have write permission
       S_IXOTH      00001   others have execute permission

这些都是八进制数。

oct(16877)相当于0o40755。这意味着以下位有效:

  • 40000S_IFDIR:目录
  • 700,表示所有者可以读取,写入和执行
  • 50,表示该组可以读取和执行,但不能写入。
  • 5,这意味着世界可以阅读和执行,但不能写。

755是目录的模式。)

您可以做的一些事情:

  1. 链接文档中的stat联机帮助页,或添加我粘贴的代码。然后,您可以使用

    self.assertEqual(0o40755, os.stat(my_directory).st_mode)
    

    相反,这意味着完全相同,但调试变得更容易。

  2. 您可以使用ctypes模块自行实现位域。 python wiki有更多信息。 (搜索“位字段”。)
  3. 您可以将16877或0o40755(以及其他输出)作为常量变量的值,也许是全局变量。

    DIR_755 = 0o40755
    

    然后,你可以这样做:

    self.assertEqual(DIR_755, os.stat(my_directory).st_mode)
    

    检查模式是否正确。

  4. 您可以制作代码和值的字典:

    st_mode_vals = {
        "S_IFMT": 0170000,  # Or instead, "filetype_bitmask"
        "S_IFSOCK": 0140000,  # Or instead, "socket"
        ...
        "S_IXOTH": 0o1  # Or instead, "other_x"
    }
    

    然后您可以将它们定义为:

    DIR_755 = st_mode_vals["directory"] +\
              st_mode_vals["usr_rwx"] +\
              st_mode_vals["grp_r"] + st_mode_vals["grp_x"] +\
              st_mode_vals["oth_r"] + st_mode_vals["oth_x"]
    self.assertEqual(DIR_755, os.stat(my_directory).st_mode)
    
  5. 如果某些代码经常被重复使用,我会亲自使用#1(链接到文档)和#3。对于所有这些,也许你可以添加一个注释来表示十进制的值吗?

    编辑:在我发布之前,我没有看到添加的答案。我不知道stat模块做了什么,所以我没有想到它。无论哪种方式,我想我仍然会使用#1,也许#3。然而,他所写的内容肯定会取代#4(字典)作为另一种选择,而且确实会好得多。

答案 2 :(得分:2)

如果我可以稍微扩展一下这个问题并将其理解为“是否有更可读的方法来检查文件模式?”,那么我建议添加一个自定义断言。目标:

self.assertFileMode(my_directory, user="rwx", group="rx", others="rx")

怎么做。

让我们把这个断言放在mixin中:

import os
import stat

class FileAssertions(object):
    FILE_PERMS = {
        'user': {'r': stat.S_IRUSR, 'w': stat.S_IWUSR, 'x': stat.S_IXUSR, 's': stat.S_ISUID},
        'group': {'r': stat.S_IRGRP, 'w': stat.S_IWGRP, 'x': stat.S_IXGRP, 's': stat.S_ISGID},
        'others': {'r': stat.S_IROTH, 'w': stat.S_IWOTH, 'x': stat.S_IXOTH},
    }

    def assertFileMode(self, path, **kwargs):
        mode = os.stat(path).st_mode
        for key, perm_defs in self.FILE_PERMS.items():
            expected = kwargs.pop(key, None)
            if expected is not None:
                actual_perms = mode & sum(perm_defs.values())
                expected_perms = sum(perm_defs[flag] for flag in expected)

                if actual_perms != expected_perms:
                    msg = '{key} permissions: {expected} != {actual} for {path}'.format(
                        key=key, path=path,
                        expected=''.join(sorted(expected)),
                        actual=''.join(sorted(flag for flag, value in perm_defs.items()
                                              if value & mode != 0))
                    )
                    raise self.failureException(msg)
        if kwargs:
            raise TypeError('assertFileMode: unknown arguments %s' % ', '.join(kwargs))

使用

现在,我们测试一些文件模式怎么样?

# We use our mixin
class MyTestCase(FileAssertions, TestCase):
    def test_some_paths(self):
        # Test all permissions
        self.assertFileMode('/foo/bar', user='rwx', group='rx', others='')

        # Only test user permissions
        self.assertFileMode('/foo/bar', user='rwx')

        # We support the suid/sgid bits as well
        self.assertFileMode('/foo/bar', user='rwxs', group='rxs', others='rx')

示例输出:

AssertionError: user permissions: rw != rwx for /foo/bar

备注:

  • 仅测试给予该方法的权限。要测试没有权限,请传递一个空字符串。
  • 大多数复杂性来自于生成用户友好的消息。
  • 权限按错误消息的字母顺序排序,因此更容易进行眼球比较。
  • 为了简单起见,我没有处理sticky bit
  • 的测试

答案 3 :(得分:1)

self.assertEqual(16877, os.stat(my_directory).st_mode)
  

只有老派unix专家能够流畅地解读整数值16877。

实际上,老派的unix专家可能会在同一条船上,因为这些东西都以八进制显示。

我会:

  • 切换到八进制以指定模式
  • 添加文字表示和评论

这样的事情:

# 'my_directory' should be a directory with full permissions for user and
# read/execute permissions for group and other
# drwxr-xr-x
self.assertEqual(0o40755, os.stat(my_directory).st_mode)