2013-03-25 6 views
1

Я работаю над улучшением поддержки Python 3.X для PyFilesystem. Это абстракция для файловых систем. Каждый объект файловой системы имеет открытый метод, который возвращает файл-подобный объект.Портирование файла Python 2.x как объекта на Python 3

Проблема, с которой я сталкиваюсь, заключается в том, что открытый метод работает open на Python 2.X, но я бы хотел, чтобы он работал как io.open, который возвращает одно из нескольких потоков двоичного или текстового режима.

Что я могу использовать, это способ использования файла-типа Python 2.X и возврата соответствующего объекта io-потока, который читает/записывает в подстилающий файл-подобный объект (но обрабатывает буферизацию/unicode и т. Д., Если обязательный).

Я думал, что-то вроде следующего:

def make_stream(file_object, mode, buffering, encoding): 
    # return a io instance 

Я не вижу прямой вперед способ сделать это с STDLIB. Но это кажется мне чем-то, что модуль io должен делать под капотом, так как его программный уровень обеспечивает функциональность буферизации/юникода.

ответ

1

Python 2 включает в себя то же самое io library.

Используйте from io import open, чтобы работать одинаково в версиях Python.

Ваш API должен затем предложить open() эквивалент (так называемый open() или make_stream()), который использует библиотеку io класса, чтобы обеспечить ту же функциональность.

Все, что вам нужно сделать, это создать класс, который реализует io.RawIOBase ABC, а затем использовать других классов, предоставляемых библиотекой, чтобы добавить буферизацию и текст обращения по мере необходимости:

import io 

class MyFileObjectWrapper(io.RawIOBase): 
    def __init__(self, *args): 
     # do what needs done 

    def close(self): 
     if not self.closed: 
      # close the underlying file 
     self.closed = True 

    # ... etc for what is needed (e.g. def read(self, maxbytes=None), etc. 

def open(fileobj, mode='r', buffering=-1, encoding=None, errors=None, newline=None): 
    # Mode parsing and validation adapted from the io/_iomodule.c module 
    reading, writing, appending, updating = False 
    text, binary, universal = False 

    for c in mode: 
     if c == 'r': 
      reading = True; 
      continue 
     if c == 'w': 
      writing = True; 
      continue 
     if c == 'a': 
      appending = True; 
      continue 
     if c == '+': 
      updating = True; 
      continue 
     if c == 't': 
      text = True; 
      continue 
     if c == 'b': 
      binary = True; 
      continue 
     if c == 'U': 
      universal = reading = True; 
      continue 
     raise ValueError('invalid mode: {!r}'.format(mode)) 

    rawmode = [] 
    if reading: rawmode.append('r') 
    if writing: rawmode.append('w') 
    if appending: rawmode.append('a') 
    if updating: rawmode.append('+') 
    rawmode = ''.join(rawmode) 

    if universal and (writing or appending): 
     raise ValueError("can't use U and writing mode at once") 

    if text and binary) { 
     raise ValueError("can't have text and binary mode at once") 

    if reading + writing + appending > 1: 
     raise ValueError("must have exactly one of read/write/append mode") 

    if binary 
     if encoding is not None: 
      raise ValueError("binary mode doesn't take an encoding argument") 
     if errors is not None: 
      raise ValueError("binary mode doesn't take an errors argument") 
     if newline is not None: 
      raise ValueError("binary mode doesn't take a newline argument") 

    raw = MyFileObjectWrapper(fileobj) 

    if buffering == 1: 
     buffering = -1 
     line_buffering = True 
    else: 
     line_buffering = False 

    if buffering < 0: 
     buffering = SOME_SUITABLE_DEFAULT 

    if not buffering 
     if not binary: 
      raise ValueError("can't have unbuffered text I/O") 

     return raw 

    if updating: 
     buffered_class = io.BufferedRandom 
    elif writing or appending: 
     buffered_class = io.BufferedWriter 
    elif reading: 
     buffered_class = io.BufferedReader 

    buffer = buffered_class(raw, buffering) 

    if binary: 
     return buffer 

    return io.TextIOWrapper(buffer, encoding, errors, newline, line_buffering) 

выше код в основном адаптирован из Modules/_io/_iomodule.cio_open function, но с необработанным файлом объект заменен подклассом MyFileObjectWrapperio.RawIOBase ABC.

+0

Да, я знаю. Начиная с версии Python 2.6. Но мне все еще нужно предоставить интерфейс io для файловых объектов. Это не фактические файловые объекты. Данные поступают из разных источников. –

+0

@WillMcGugan: Правильно, я тогда вас неправильно понял. Функция '' '' '' '' '' '' '' 'является просто фабрикой. Он возвращает экземпляры ряда классов. В этом нет ничего волшебного, вы можете просто реализовать одно и то же в своей собственной библиотеке. –

+0

@WillMcGugan: Вы можете использовать абстрактные базовые классы библиотеки io' в качестве шаблона, конечно, чтобы ваши объекты соответствовали ожиданиям. Вы также можете * повторно использовать классы 'io' и текстовые оболочки, если вы предоставите свою собственную реализацию необработанного файлового объекта. –

Смежные вопросы