diff --git a/.github/workflows/cs102.yml b/.github/workflows/cs102.yml index 4509ac4..1abff40 100644 --- a/.github/workflows/cs102.yml +++ b/.github/workflows/cs102.yml @@ -7,10 +7,10 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - name: Set up Python 3.8.6 + - name: Set up Python 3.10.10 uses: actions/setup-python@v2 with: - python-version: '3.8.6' + python-version: '3.10.10' - name: Install dependencies run: | python -m pip install --upgrade pip diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/857l.iml b/.idea/857l.iml new file mode 100644 index 0000000..8e5446a --- /dev/null +++ b/.idea/857l.iml @@ -0,0 +1,14 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..aad1270 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,21 @@ + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..592a42b --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..1d9aaec --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/homework04/.idea/.gitignore b/homework04/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/homework04/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/homework04/.idea/homework04.iml b/homework04/.idea/homework04.iml new file mode 100644 index 0000000..8e5446a --- /dev/null +++ b/homework04/.idea/homework04.iml @@ -0,0 +1,14 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/homework04/.idea/inspectionProfiles/profiles_settings.xml b/homework04/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/homework04/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/homework04/.idea/misc.xml b/homework04/.idea/misc.xml new file mode 100644 index 0000000..a4fea96 --- /dev/null +++ b/homework04/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/homework04/.idea/modules.xml b/homework04/.idea/modules.xml new file mode 100644 index 0000000..caedf72 --- /dev/null +++ b/homework04/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/homework04/pyvcs.egg-info/PKG-INFO b/homework04/pyvcs.egg-info/PKG-INFO new file mode 100644 index 0000000..78f5b9f --- /dev/null +++ b/homework04/pyvcs.egg-info/PKG-INFO @@ -0,0 +1,13 @@ +Metadata-Version: 2.1 +Name: pyvcs +Version: 0.1.0 +Summary: The stupid content tracker +Home-page: https://github.com/Dementiy/pybook-assignments +Author: Dmitrii Sorokin +Author-email: dementiy@yandex.ru +License: GPLv3 +Platform: UNKNOWN +Requires-Python: >=3.6.0 + +UNKNOWN + diff --git a/homework04/pyvcs.egg-info/SOURCES.txt b/homework04/pyvcs.egg-info/SOURCES.txt new file mode 100644 index 0000000..bc5e160 --- /dev/null +++ b/homework04/pyvcs.egg-info/SOURCES.txt @@ -0,0 +1,15 @@ +setup.py +pyvcs/__init__.py +pyvcs/__main__.py +pyvcs/cli.py +pyvcs/index.py +pyvcs/objects.py +pyvcs/porcelain.py +pyvcs/refs.py +pyvcs/repo.py +pyvcs/tree.py +pyvcs.egg-info/PKG-INFO +pyvcs.egg-info/SOURCES.txt +pyvcs.egg-info/dependency_links.txt +pyvcs.egg-info/entry_points.txt +pyvcs.egg-info/top_level.txt \ No newline at end of file diff --git a/homework04/pyvcs.egg-info/dependency_links.txt b/homework04/pyvcs.egg-info/dependency_links.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/homework04/pyvcs.egg-info/dependency_links.txt @@ -0,0 +1 @@ + diff --git a/homework04/pyvcs.egg-info/entry_points.txt b/homework04/pyvcs.egg-info/entry_points.txt new file mode 100644 index 0000000..bba7a0d --- /dev/null +++ b/homework04/pyvcs.egg-info/entry_points.txt @@ -0,0 +1,3 @@ +[console_scripts] +pyvcs = pyvcs.__main__:main + diff --git a/homework04/pyvcs.egg-info/top_level.txt b/homework04/pyvcs.egg-info/top_level.txt new file mode 100644 index 0000000..809a5ab --- /dev/null +++ b/homework04/pyvcs.egg-info/top_level.txt @@ -0,0 +1 @@ +pyvcs diff --git a/homework04/pyvcs/__main__.py b/homework04/pyvcs/__main__.py index 797f8e9..4d941b2 100644 --- a/homework04/pyvcs/__main__.py +++ b/homework04/pyvcs/__main__.py @@ -116,6 +116,7 @@ def add_write_tree_subparser(subparsers) -> None: def add_commit_tree_subparser(subparsers) -> None: + # FIXME: Add author commit_tree_subparser = subparsers.add_parser("commit-tree", help="Create a new commit object.") commit_tree_subparser.add_argument("tree", help="An existing tree object") commit_tree_subparser.add_argument("-p", dest="parent", help="Id of a parent commit object") diff --git a/homework04/pyvcs/index.py b/homework04/pyvcs/index.py index 85a5e91..658de35 100644 --- a/homework04/pyvcs/index.py +++ b/homework04/pyvcs/index.py @@ -25,30 +25,93 @@ class GitIndexEntry(tp.NamedTuple): name: str def pack(self) -> bytes: - # PUT YOUR CODE HERE - ... + # pack the data + return ( + struct.pack( + f">LLLLLLLLLL20sH{len(self.name.encode())}s", *self[:-1], self.name.encode() + ) + + b"\x00\x00\x00" + ) @staticmethod def unpack(data: bytes) -> "GitIndexEntry": - # PUT YOUR CODE HERE - ... + size = struct.calcsize(">LLLLLLLLLL20sH") + # unpack the data + values = struct.unpack(f">LLLLLLLLLL20sH", data[:size]) + # add in tuple value below + values += (data[size:].split(b"\x00\x00\x00")[0].decode(),) + return GitIndexEntry( + *values, + ) def read_index(gitdir: pathlib.Path) -> tp.List[GitIndexEntry]: - # PUT YOUR CODE HERE - ... + if not (gitdir / "index").exists(): + return [] + + with (gitdir / "index").open("rb") as f: + data = f.read() + if data[:4] != b"DIRC": + raise Exception("Not a valid index file") + version, count = struct.unpack(">LL", data[4:12]) + if version != 2: + raise Exception("Unsupported index version") + entries = [] + offset = 12 + for _ in range(count): + entry = GitIndexEntry.unpack(data[offset:]) + entries.append(entry) + offset += 62 + len(entry.name.encode()) + 3 + return entries def write_index(gitdir: pathlib.Path, entries: tp.List[GitIndexEntry]) -> None: - # PUT YOUR CODE HERE - ... + data = b"DIRC" + struct.pack(">LL", 2, len(entries)) + for entry in entries: + data += entry.pack() + with (gitdir / "index").open("wb") as f: + f.write(data) + f.write(hashlib.sha1(data).digest()) def ls_files(gitdir: pathlib.Path, details: bool = False) -> None: - # PUT YOUR CODE HERE - ... + entries = read_index(gitdir) + for entry in entries: + if details: + print(f"{entry.mode:o} {entry.sha1.hex()} 0\t{entry.name}") + else: + print(entry.name) def update_index(gitdir: pathlib.Path, paths: tp.List[pathlib.Path], write: bool = True) -> None: - # PUT YOUR CODE HERE - ... + entries = read_index(gitdir) + for path in paths: + if not path.exists(): + raise Exception(f"Path {path} does not exist") + with path.open("rb") as f: + data = f.read() + sha1 = hash_object(data, "blob", write=True) + for entry in entries: + if entry.name == str(path): + entries.remove(entry) + break + entries.append( + GitIndexEntry( + int(path.stat().st_ctime), + int(path.stat().st_ctime_ns % 1000000000), + int(path.stat().st_mtime), + int(path.stat().st_mtime_ns % 1000000000), + path.stat().st_dev, + path.stat().st_ino, + path.stat().st_mode, + path.stat().st_uid, + path.stat().st_gid, + path.stat().st_size, + bytes.fromhex(sha1), + 0, + str(path).replace("\\", "/"), + ) + ) + if write: + entries.sort(key=operator.attrgetter("name")) + write_index(gitdir, entries) diff --git a/homework04/pyvcs/objects.py b/homework04/pyvcs/objects.py index 013cc8d..360258c 100644 --- a/homework04/pyvcs/objects.py +++ b/homework04/pyvcs/objects.py @@ -11,40 +11,102 @@ def hash_object(data: bytes, fmt: str, write: bool = False) -> str: - # PUT YOUR CODE HERE - ... + header = f"{fmt} {len(data)}\0".encode() + store = header + data + sha = hashlib.sha1(store).hexdigest() + if write: + gitdir = repo_find() + path = gitdir / "objects" / sha[:2] / sha[2:] + path.parent.mkdir(parents=True, exist_ok=True) + with path.open("wb") as f: + f.write(zlib.compress(store)) + return sha def resolve_object(obj_name: str, gitdir: pathlib.Path) -> tp.List[str]: - # PUT YOUR CODE HERE - ... + if len(obj_name) < 4 or len(obj_name) > 40: + raise Exception(f"Not a valid object name {obj_name}") + + objects = [] + + for i in (gitdir / "objects").iterdir(): + if i.is_dir() and i.name == obj_name[:2]: + for j in i.iterdir(): + if obj_name[2:] in j.name: + objects.append(i.name + j.name) + + if len(objects) == 0: + raise Exception(f"Not a valid object name {obj_name}") + + return objects def find_object(obj_name: str, gitdir: pathlib.Path) -> str: - # PUT YOUR CODE HERE - ... + object_new = resolve_object(obj_name, gitdir) + if len(object_new) == 1: + return object_new[0] + else: + raise Exception(f"Ambiguous object name {obj_name}") def read_object(sha: str, gitdir: pathlib.Path) -> tp.Tuple[str, bytes]: - # PUT YOUR CODE HERE - ... + object_new = find_object(sha, gitdir) + path = gitdir / "objects" / object_new[:2] / object_new[2:] + with path.open("rb") as f: + data = zlib.decompress(f.read()) + return data.split(b" ", maxsplit=1)[0].decode(), data.split(b"\0", maxsplit=1)[1] def read_tree(data: bytes) -> tp.List[tp.Tuple[int, str, str]]: - # PUT YOUR CODE HERE - ... + result = [] + while data: + mode, name_sha = data.split(b" ")[:2] + name, sha = name_sha.split(b"\0")[:2] + # print(f"Mode: {mode}, Name: {name}, SHA: {sha}") + result.append((int(oct(int(mode, 8))[2:]), name.decode(), sha[:20].hex())) + data = data[len(mode) + 2 + len(name) + 20 :] + return result def cat_file(obj_name: str, pretty: bool = True) -> None: - # PUT YOUR CODE HERE - ... + object_new = read_object(obj_name, repo_find()) + if pretty: + if object_new[0] == "commit": + print(object_new[1].decode()) + elif object_new[0] == "tree": + for i in read_tree(object_new[1]): + print(f"{str(i[0]).zfill(6)} {read_object(i[2], repo_find())[0]} {i[2]}\t{i[1]}") + elif object_new[0] == "blob": + print(object_new[1].decode()) + else: + print(object_new[1].decode()) def find_tree_files(tree_sha: str, gitdir: pathlib.Path) -> tp.List[tp.Tuple[str, str]]: - # PUT YOUR CODE HERE - ... + result = [] + for mode, name, sha in read_tree(read_object(tree_sha, gitdir)[1]): + if read_object(sha, gitdir)[0] == "tree": + tree = find_tree_files(sha, gitdir) + for i in tree: + result.append((name + "/" + i[0], i[1])) + else: + result.append((name, sha)) + return result def commit_parse(raw: bytes, start: int = 0, dct=None): - # PUT YOUR CODE HERE - ... + if dct is None: + dct = {} + if start == 0: + dct["tree"] = raw.split(b"\n", maxsplit=1)[0].decode() + if start == 1: + dct["parent"] = raw.split(b"\n", maxsplit=1)[0].decode() + if start == 2: + dct["author"] = raw.split(b"\n", maxsplit=1)[0].decode() + if start == 3: + dct["committer"] = raw.split(b"\n", maxsplit=1)[0].decode() + if start == 4: + dct["message"] = raw.split(b"\n", maxsplit=1)[0].decode() + if start == 5: + return dct + return commit_parse(raw.split(b"\n", maxsplit=1)[1], start + 1, dct) diff --git a/homework04/pyvcs/porcelain.py b/homework04/pyvcs/porcelain.py index 6f2cde2..01891c1 100644 --- a/homework04/pyvcs/porcelain.py +++ b/homework04/pyvcs/porcelain.py @@ -1,23 +1,51 @@ import os import pathlib +import shutil import typing as tp from pyvcs.index import read_index, update_index -from pyvcs.objects import commit_parse, find_object, find_tree_files, read_object +from pyvcs.objects import ( + cat_file, + commit_parse, + find_object, + find_tree_files, + read_object, +) from pyvcs.refs import get_ref, is_detached, resolve_head, update_ref from pyvcs.tree import commit_tree, write_tree def add(gitdir: pathlib.Path, paths: tp.List[pathlib.Path]) -> None: - # PUT YOUR CODE HERE - ... + update_index(gitdir, paths) def commit(gitdir: pathlib.Path, message: str, author: tp.Optional[str] = None) -> str: - # PUT YOUR CODE HERE - ... + return commit_tree(gitdir, write_tree(gitdir, read_index(gitdir)), message, author=author) def checkout(gitdir: pathlib.Path, obj_name: str) -> None: - # PUT YOUR CODE HERE - ... + ref_file = gitdir / "refs" / "heads" / obj_name + if ref_file.exists(): + with open(ref_file, "w") as f: + obj_name = f.read() + + indexes = read_index(gitdir) + for index in indexes: + if pathlib.Path(index.name).is_file(): + name = index.name.split("/") + if len(name) > 1: + shutil.rmtree(name[0]) + else: + os.remove(index.name) + + object_by_sha = read_object(obj_name, gitdir) + sha = object_by_sha[1].decode().split("\n")[0].split()[1] + + for tree_obj in find_tree_files(sha, gitdir): + name = tree_obj[0].split("/") + + if len(name) > 1: + pathlib.Path(name[0]).absolute().mkdir() + + with open(tree_obj[0], "w") as f: + f.write(read_object(tree_obj[1], gitdir)[1].decode()) diff --git a/homework04/pyvcs/refs.py b/homework04/pyvcs/refs.py index 1e45b90..7e7bdaf 100644 --- a/homework04/pyvcs/refs.py +++ b/homework04/pyvcs/refs.py @@ -3,30 +3,51 @@ def update_ref(gitdir: pathlib.Path, ref: tp.Union[str, pathlib.Path], new_value: str) -> None: - # PUT YOUR CODE HERE - ... + path = gitdir / ref + with open(path, "w") as f: + f.write(new_value) def symbolic_ref(gitdir: pathlib.Path, name: str, ref: str) -> None: - # PUT YOUR CODE HERE - ... + path = gitdir / name + with open(path, "w") as f: + f.write("ref: " + ref) -def ref_resolve(gitdir: pathlib.Path, refname: str) -> str: - # PUT YOUR CODE HERE - ... +def ref_resolve(gitdir: pathlib.Path, refname: str) -> tp.Optional[str]: + if refname == "HEAD": + refname = get_ref(gitdir) + + path = gitdir / refname + if not path.exists(): + return None + + with open(path, "r") as f: + ref = f.read().strip() + return ref def resolve_head(gitdir: pathlib.Path) -> tp.Optional[str]: - # PUT YOUR CODE HERE - ... + return ref_resolve(gitdir, "HEAD") def is_detached(gitdir: pathlib.Path) -> bool: - # PUT YOUR CODE HERE - ... + path = gitdir / "HEAD" + with open(path, "r") as f: + ref = f.read().strip() + + if ref[:5] == "ref: ": + return False + + return True def get_ref(gitdir: pathlib.Path) -> str: - # PUT YOUR CODE HERE - ... + path = gitdir / "HEAD" + with open(path, "r") as f: + ref = f.read().strip() + + if ref[:5] == "ref: ": + return ref[5:] + + return ref diff --git a/homework04/pyvcs/repo.py b/homework04/pyvcs/repo.py index cef16a6..bd3faf9 100644 --- a/homework04/pyvcs/repo.py +++ b/homework04/pyvcs/repo.py @@ -4,10 +4,39 @@ def repo_find(workdir: tp.Union[str, pathlib.Path] = ".") -> pathlib.Path: - # PUT YOUR CODE HERE - ... + # Find repository directory + workdir = pathlib.Path(workdir) + if not workdir.is_dir(): + raise NotADirectoryError(workdir) + gitdir = workdir / os.environ.get("GIT_DIR", ".git") + while not gitdir.is_dir(): + if workdir.parent == workdir: + raise Exception(f"Not a git repository") + workdir = workdir.parent + gitdir = workdir / os.environ["GIT_DIR"] + return gitdir def repo_create(workdir: tp.Union[str, pathlib.Path]) -> pathlib.Path: - # PUT YOUR CODE HERE - ... + # Create repository directory + workdir = pathlib.Path(workdir) + if not workdir.is_dir(): + raise Exception(f"{workdir} is not a directory") + gitdir = workdir / os.environ.get("GIT_DIR", ".git") + if gitdir.is_dir(): + raise FileExistsError(gitdir) + os.makedirs(gitdir) + os.makedirs(gitdir / "branches") + os.makedirs(gitdir / "objects") + os.makedirs(gitdir / "refs" / "tags") + os.makedirs(gitdir / "refs" / "heads") + with open(gitdir / "HEAD", "wt") as f: + f.write("ref: refs/heads/master\n") + with open(gitdir / "config", "wt") as f: + f.write( + "[core]\n\trepositoryformatversion = 0\n\tfilemode = true\n\tbare = false\n\tlogallrefupdates = false\n" + ) + with open(gitdir / "description", "wt") as f: + f.write("Unnamed pyvcs repository.\n") + + return gitdir diff --git a/homework04/pyvcs/tree.py b/homework04/pyvcs/tree.py index f79b026..4ece431 100644 --- a/homework04/pyvcs/tree.py +++ b/homework04/pyvcs/tree.py @@ -10,8 +10,31 @@ def write_tree(gitdir: pathlib.Path, index: tp.List[GitIndexEntry], dirname: str = "") -> str: - # PUT YOUR CODE HERE - ... + tree = b"" + for entry in index: + position = entry.name.rfind("/") + dirname = "" if position == -1 else entry.name[:position] + # print(entry.name) + # if dirname == "": + # tree += f"{entry.mode} {entry.name}\0{bytes.hex(entry.sha1)}" + # else: + # tree += f"{entry.mode} {entry.name[len(dirname)+1:]}\0{entry.sha1}" + if dirname == "": + tree += oct(entry.mode)[2:].encode() + b" " + tree += entry.name.encode() + b"\0" + tree += entry.sha1 + else: + temp_object = b"" + temp_object += oct(entry.mode)[2:].encode() + b" " + temp_object += entry.name[len(dirname) + 1 :].encode() + b"\0" + temp_object += entry.sha1 + sha1 = hash_object(temp_object, "tree", True) + + tree += oct(stat.S_IFDIR | 0o000)[2:].encode() + b" " + tree += dirname.encode() + b"\0" + tree += bytes.fromhex(sha1) + + return hash_object(tree, "tree", True) def commit_tree( @@ -21,5 +44,15 @@ def commit_tree( parent: tp.Optional[str] = None, author: tp.Optional[str] = None, ) -> str: - # PUT YOUR CODE HERE - ... + if author is None: + author = f"{os.environ['GIT_AUTHOR_NAME']} <{os.environ['GIT_AUTHOR_EMAIL']}>" + + timestamp = int(time.mktime(time.localtime())) + + commit = f"tree {tree}\n" + if parent: + commit += f"parent {parent}\n" + commit += f"author {author} {timestamp} +0300\n" + commit += f"committer {author} {timestamp} +0300\n\n" + commit += f"{message}\n" + return hash_object(commit.encode("ascii"), "commit", True) diff --git a/homework04/setup.py b/homework04/setup.py index 51dc915..56f124a 100644 --- a/homework04/setup.py +++ b/homework04/setup.py @@ -1,6 +1,5 @@ -from setuptools import setup - import pyvcs +from setuptools import setup AUTHOR = "Dmitrii Sorokin" AUTHOR_EMAIL = "dementiy@yandex.ru" diff --git a/homework04/tests/test_index.py b/homework04/tests/test_index.py index eaf5576..0905b61 100644 --- a/homework04/tests/test_index.py +++ b/homework04/tests/test_index.py @@ -3,9 +3,8 @@ import unittest from unittest.mock import patch -from pyfakefs.fake_filesystem_unittest import TestCase - import pyvcs +from pyfakefs.fake_filesystem_unittest import TestCase from pyvcs.index import GitIndexEntry, ls_files, read_index, update_index, write_index from pyvcs.repo import repo_create diff --git a/homework04/tests/test_objects.py b/homework04/tests/test_objects.py index 5cbad4f..aadf5e1 100644 --- a/homework04/tests/test_objects.py +++ b/homework04/tests/test_objects.py @@ -5,9 +5,8 @@ import zlib from unittest.mock import patch -from pyfakefs.fake_filesystem_unittest import TestCase - import pyvcs +from pyfakefs.fake_filesystem_unittest import TestCase from pyvcs import index, objects, porcelain, repo, tree diff --git a/homework04/tests/test_porcelain.py b/homework04/tests/test_porcelain.py index a65eb51..758740f 100644 --- a/homework04/tests/test_porcelain.py +++ b/homework04/tests/test_porcelain.py @@ -3,9 +3,8 @@ import unittest from unittest.mock import patch -from pyfakefs.fake_filesystem_unittest import TestCase - import pyvcs +from pyfakefs.fake_filesystem_unittest import TestCase from pyvcs.porcelain import add, checkout, commit from pyvcs.repo import repo_create diff --git a/homework04/tests/test_refs.py b/homework04/tests/test_refs.py index 8012f57..0dc4337 100644 --- a/homework04/tests/test_refs.py +++ b/homework04/tests/test_refs.py @@ -1,8 +1,7 @@ import unittest -from pyfakefs.fake_filesystem_unittest import TestCase - import pyvcs +from pyfakefs.fake_filesystem_unittest import TestCase from pyvcs.refs import get_ref, is_detached, ref_resolve, resolve_head, update_ref from pyvcs.repo import repo_create diff --git a/homework04/tests/test_repo.py b/homework04/tests/test_repo.py index 4107078..e534eb1 100644 --- a/homework04/tests/test_repo.py +++ b/homework04/tests/test_repo.py @@ -2,7 +2,6 @@ import pathlib from pyfakefs.fake_filesystem_unittest import TestCase - from pyvcs import repo diff --git a/homework04/tests/test_tree.py b/homework04/tests/test_tree.py index 1c32a62..8ac69ae 100644 --- a/homework04/tests/test_tree.py +++ b/homework04/tests/test_tree.py @@ -4,9 +4,8 @@ import unittest from unittest.mock import patch -from pyfakefs.fake_filesystem_unittest import TestCase - import pyvcs +from pyfakefs.fake_filesystem_unittest import TestCase from pyvcs.index import read_index, update_index from pyvcs.repo import repo_create from pyvcs.tree import commit_tree, write_tree