Python デザインパターン サンプルコード Facade
Mark Summerfield『実践 Python 3』デザインパターンのサンプルコード
Python3(3.11)で動くソースコード(.pyファイル .ipynbファイル)あります
「anaconda3」on .py「PyCharm」.ipynb「Jupyter Notebook」
(2023-11-17)Python3.11で動作確認済み
Archive (内容省略)class Archive は,圧縮・解凍に関わる標準ライブラリにアクセスするインターフェイス
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
#!/usr/bin/env python3 # Copyright c 2012-13 Qtrac Ltd. All rights reserved. # This program or module is free software: you can redistribute it # and/or modify it under the terms of the GNU General Public License as # published by the Free Software Foundation, either version 3 of the # License, or (at your option) any later version. It is provided for # educational purposes and is distributed in the hope that it will be # useful, but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. import contextlib import gzip import os import re import string import tarfile import zipfile class Archive: def __init__(self, filename): self._names = None self._unpack = None self._file = None self.filename = filename @property def filename(self): return self.__filename @filename.setter def filename(self, name): self.close() self.__filename = name def close(self): if self._file is not None: self._file.close() self._names = self._unpack = self._file = None def names(self): if self._file is None: self._prepare() return self._names() def unpack(self): if self._file is None: self._prepare() self._unpack() def _prepare(self): if self.filename.endswith((".tar.gz", ".tar.bz2", ".tar.xz", ".zip")): self._prepare_tarball_or_zip() elif self.filename.endswith(".gz"): self._prepare_gzip() else: raise ValueError("unreadable: {}".format(self.filename)) def _prepare_tarball_or_zip(self): def safe_extractall(): unsafe = [] for name in self.names(): if not self.is_safe(name): unsafe.append(name) if unsafe: raise ValueError("unsafe to unpack: {}".format(unsafe)) self._file.extractall() if self.filename.endswith(".zip"): self._file = zipfile.ZipFile(self.filename) self._names = self._file.namelist self._unpack = safe_extractall else: # Ends with .tar.gz, .tar.bz2, or .tar.xz suffix = os.path.splitext(self.filename)[1] self._file = tarfile.open(self.filename, "r:" + suffix[1:]) self._names = self._file.getnames self._unpack = safe_extractall def _prepare_gzip(self): self._file = gzip.open(self.filename) filename = self.filename[:-3] self._names = lambda: [filename] def extractall(): with open(filename, "wb") as file: file.write(self._file.read()) self._unpack = extractall def is_safe(self, filename): return not (filename.startswith(("/", "\\")) or (len(filename) > 1 and filename[1] == ":" and filename[0] in string.ascii_letter) or re.search(r"[.][.][/\\]", filename)) def __enter__(self): return self def __exit__(self, exc_type, exc_value, traceback): self.close() def __str__(self): return "{}({})".format(self.filename, self._file is not None) if __name__ == "__main__": # This code is designed to work with 3.1+, so can't use # os.makedirs()'s exist_ok keyword argument, can't use # zipfile.ZipFile as a context manager, and can't use text mode for # gzip. import errno import os import shutil import tempfile fromPath = os.path.dirname(os.path.abspath(__file__)) toPath = os.path.join(tempfile.gettempdir(), "unpack") try: os.makedirs(toPath) except OSError as err: if err.errno != errno.EEXIST: raise zipFilename = os.path.join(toPath, "test.zip") zipNames = ["Bag1.py", "Bag2.py", "Bag3.py"] tarFilename = os.path.join(toPath, "test.tar.gz") tarNames = ["genome1.py", "genome2.py", "genome3.py"] gzFilename = os.path.join(toPath, "hello.pyw.gz") gzName = "hello.pyw" file = None try: file = zipfile.ZipFile(zipFilename, "w", zipfile.ZIP_DEFLATED) for name in zipNames: file.write(name) finally: if file is not None: file.close() file = None try: file = tarfile.open(tarFilename, "w:gz") for name in tarNames: file.add(name) finally: if file is not None: file.close() file = None try: file = gzip.open(gzFilename, "w") with open(gzName, "rb") as infile: file.write(infile.read()) finally: if file is not None: file.close() os.chdir(toPath) with Archive(zipFilename) as archive: print(archive.names()) assert archive.names() == zipNames archive.unpack() archive.filename = tarFilename print(archive.names()) assert archive.names() == tarNames archive.unpack() archive.filename = gzFilename archive.unpack() # print(toPath) # shutil.rmtree(toPath)