2015-09-16 2 views
1

У меня есть код, который проверяет st_mode файла:Лучше assertEqual() для os.stat (Myfile) .st_mode

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

только старые школьные специалисты Юниксовые способны расшифровать целое значение 16877 свободно.

Есть ли более читаемый способ проверить именно это значение?

+0

Возможно, в зависимости от того, что вы подразумеваете под понятием «читаемый». Код, который у вас есть в вашем вопросе, скрывает много вещей за кулисами. Например: 'os.stat (my_directory)' возвращает объект 'os.stat_return()', который имеет несколько свойств, включая 'st_mode'. Что касается демистификации «16877», вы можете присвоить значение переменной, которая названа соответствующим образом, но это все, что вы могли бы сделать, поскольку свойство 'st_mode' объекта' os.stat_return() 'всегда будет числовым значением. –

+0

Установлена ​​ли ваша система и проверьте это состояние? У вас есть функция, которая проверяет состояние? Не могли бы вы использовать это в утверждении? У вас есть имя для этого состояния в вашей системе (например, только для владельца)? –

+0

@PeterWood да, моя система устанавливает это состояние. Да, он проверяет это состояние. Это вышеприведенная строка. Проверить это невозможно. Но тест, который содержит указанную выше строку. Пока нет имени. Но хорошая идея. Название государства было бы еще лучше. Спасибо – guettli

ответ

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.
+0

Да, это отличное многоразовое решение. Было бы неплохо иметь его в качестве устанавливаемой в программе библиотеки. – guettli

+0

Спасибо.Я считаю, что действительно есть место для пакета python, который добавит кучу полезных - могу ли я сказать семантические утверждения, особенно о манипуляциях с файлами и контенте, временных каталогах ... Правильное использование правильной документации и тщательного тестирования является слишком большим стараюсь для себя в данный момент. – spectras

+0

Кстати, я тем самым помещаю код в свой ответ под общественным достоянием. Делай все, что хочешь. Кредит оценивается, но не является обязательным. – spectras

6

Вы можете использовать определенные константы. Их можно найти в stat (docs). К ним относятся:

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) 
3

Here «s некоторая информация о st_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. Это означает, что следующие биты активны:

  • 40000 или S_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) 
    

Я лично использую # 1 (ссылка на документацию), с № 3, если есть определенные коды, которые часто используются повторно. Для всех из них, возможно, вы можете добавить комментарий, указывающий значение в десятичной форме, тоже?

Редактировать: Я не видел ответа, который был добавлен до того, как я опубликовал. Я понятия не имел, что сделал модуль stat, поэтому я не думал об этом. В любом случае, я думаю, что все равно буду использовать # 1 и, возможно, № 3. Однако то, что он написал, определенно заменит № 4 (словарь) в качестве другого варианта и будет намного лучше.

+0

Спасибо за ваше мнение и предоставленные варианты. Однако я хотел бы поделиться некоторыми мыслями об этом. Обычно использование библиотечных констант лучше, чем определение ваших. Вот почему: во-первых, зачем переопределять то, что уже существует? Во-вторых, если что-то изменится (предположим, что новая версия unix имеет новые константы разрешений, или os.stat начал использовать собственный формат, а не unix one), то в случае системных/библиотечных констант код будет работать, но если вы используете ваши собственные константы, то вам придется изменить их в коде, или, что еще хуже, вы пропустите его, и вам будет сложно найти ошибки или утечки безопасности. – sbeliakov

+0

Это то, что я не рассматривал. Я подумал, что вариант №1 был лучшим, потому что мне показалось наиболее понятным для большинства программистов, по сравнению с S_IFDIR и т. Д. Именно по этой причине я дал альтернативные имена в словаре. Но я вижу вашу точку в ремонтопригодности и соглашаюсь. Спасибо. –

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) 
Смежные вопросы