Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/git/objects/base.py: 69%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# Copyright (C) 2008, 2009 Michael Trier (mtrier@gmail.com) and contributors
2#
3# This module is part of GitPython and is released under the
4# 3-Clause BSD License: https://opensource.org/license/bsd-3-clause/
6__all__ = ["Object", "IndexObject"]
8import os.path as osp
10import gitdb.typ as dbtyp
12from git.exc import WorkTreeRepositoryUnsupported
13from git.util import LazyMixin, bin_to_hex, join_path_native, stream_copy
15from .util import get_object_type_by_name
17# typing ------------------------------------------------------------------
19from typing import Any, TYPE_CHECKING, Union
21from git.types import AnyGitObject, GitObjectTypeString, PathLike
23if TYPE_CHECKING:
24 from gitdb.base import OStream
26 from git.refs.reference import Reference
27 from git.repo import Repo
29 from .blob import Blob
30 from .submodule.base import Submodule
31 from .tree import Tree
33IndexObjUnion = Union["Tree", "Blob", "Submodule"]
35# --------------------------------------------------------------------------
38class Object(LazyMixin):
39 """Base class for classes representing git object types.
41 The following four leaf classes represent specific kinds of git objects:
43 * :class:`Blob <git.objects.blob.Blob>`
44 * :class:`Tree <git.objects.tree.Tree>`
45 * :class:`Commit <git.objects.commit.Commit>`
46 * :class:`TagObject <git.objects.tag.TagObject>`
48 See :manpage:`gitglossary(7)` on:
50 * "object": https://git-scm.com/docs/gitglossary#def_object
51 * "object type": https://git-scm.com/docs/gitglossary#def_object_type
52 * "blob": https://git-scm.com/docs/gitglossary#def_blob_object
53 * "tree object": https://git-scm.com/docs/gitglossary#def_tree_object
54 * "commit object": https://git-scm.com/docs/gitglossary#def_commit_object
55 * "tag object": https://git-scm.com/docs/gitglossary#def_tag_object
57 :note:
58 See the :class:`~git.types.AnyGitObject` union type of the four leaf subclasses
59 that represent actual git object types.
61 :note:
62 :class:`~git.objects.submodule.base.Submodule` is defined under the hierarchy
63 rooted at this :class:`Object` class, even though submodules are not really a
64 type of git object. (This also applies to its
65 :class:`~git.objects.submodule.root.RootModule` subclass.)
67 :note:
68 This :class:`Object` class should not be confused with :class:`object` (the root
69 of the class hierarchy in Python).
70 """
72 NULL_HEX_SHA = "0" * 40
73 NULL_BIN_SHA = b"\0" * 20
75 TYPES = (
76 dbtyp.str_blob_type,
77 dbtyp.str_tree_type,
78 dbtyp.str_commit_type,
79 dbtyp.str_tag_type,
80 )
82 __slots__ = ("repo", "binsha", "size")
84 type: Union[GitObjectTypeString, None] = None
85 """String identifying (a concrete :class:`Object` subtype for) a git object type.
87 The subtypes that this may name correspond to the kinds of git objects that exist,
88 i.e., the objects that may be present in a git repository.
90 :note:
91 Most subclasses represent specific types of git objects and override this class
92 attribute accordingly. This attribute is ``None`` in the :class:`Object` base
93 class, as well as the :class:`IndexObject` intermediate subclass, but never
94 ``None`` in concrete leaf subclasses representing specific git object types.
96 :note:
97 See also :class:`~git.types.GitObjectTypeString`.
98 """
100 def __init__(self, repo: "Repo", binsha: bytes) -> None:
101 """Initialize an object by identifying it by its binary sha.
103 All keyword arguments will be set on demand if ``None``.
105 :param repo:
106 Repository this object is located in.
108 :param binsha:
109 20 byte SHA1
110 """
111 super().__init__()
112 self.repo = repo
113 self.binsha = binsha
114 assert len(binsha) == 20, "Require 20 byte binary sha, got %r, len = %i" % (
115 binsha,
116 len(binsha),
117 )
119 @classmethod
120 def new(cls, repo: "Repo", id: Union[str, "Reference"]) -> AnyGitObject:
121 """
122 :return:
123 New :class:`Object` instance of a type appropriate to the object type behind
124 `id`. The id of the newly created object will be a binsha even though the
125 input id may have been a `~git.refs.reference.Reference` or rev-spec.
127 :param id:
128 :class:`~git.refs.reference.Reference`, rev-spec, or hexsha.
130 :note:
131 This cannot be a ``__new__`` method as it would always call :meth:`__init__`
132 with the input id which is not necessarily a binsha.
133 """
134 return repo.rev_parse(str(id))
136 @classmethod
137 def new_from_sha(cls, repo: "Repo", sha1: bytes) -> AnyGitObject:
138 """
139 :return:
140 New object instance of a type appropriate to represent the given binary sha1
142 :param sha1:
143 20 byte binary sha1.
144 """
145 if sha1 == cls.NULL_BIN_SHA:
146 # The NULL binsha is always the root commit.
147 return get_object_type_by_name(b"commit")(repo, sha1)
148 # END handle special case
149 oinfo = repo.odb.info(sha1)
150 inst = get_object_type_by_name(oinfo.type)(repo, oinfo.binsha)
151 inst.size = oinfo.size
152 return inst
154 def _set_cache_(self, attr: str) -> None:
155 """Retrieve object information."""
156 if attr == "size":
157 oinfo = self.repo.odb.info(self.binsha)
158 self.size = oinfo.size # type: int
159 else:
160 super()._set_cache_(attr)
162 def __eq__(self, other: Any) -> bool:
163 """:return: ``True`` if the objects have the same SHA1"""
164 if not hasattr(other, "binsha"):
165 return False
166 return self.binsha == other.binsha
168 def __ne__(self, other: Any) -> bool:
169 """:return: ``True`` if the objects do not have the same SHA1"""
170 if not hasattr(other, "binsha"):
171 return True
172 return self.binsha != other.binsha
174 def __hash__(self) -> int:
175 """:return: Hash of our id allowing objects to be used in dicts and sets"""
176 return hash(self.binsha)
178 def __str__(self) -> str:
179 """:return: String of our SHA1 as understood by all git commands"""
180 return self.hexsha
182 def __repr__(self) -> str:
183 """:return: String with pythonic representation of our object"""
184 return '<git.%s "%s">' % (self.__class__.__name__, self.hexsha)
186 @property
187 def hexsha(self) -> str:
188 """:return: 40 byte hex version of our 20 byte binary sha"""
189 # b2a_hex produces bytes.
190 return bin_to_hex(self.binsha).decode("ascii")
192 @property
193 def data_stream(self) -> "OStream":
194 """
195 :return:
196 File-object compatible stream to the uncompressed raw data of the object
198 :note:
199 Returned streams must be read in order.
200 """
201 return self.repo.odb.stream(self.binsha)
203 def stream_data(self, ostream: "OStream") -> "Object":
204 """Write our data directly to the given output stream.
206 :param ostream:
207 File-object compatible stream object.
209 :return:
210 self
211 """
212 istream = self.repo.odb.stream(self.binsha)
213 stream_copy(istream, ostream)
214 return self
217class IndexObject(Object):
218 """Base for all objects that can be part of the index file.
220 The classes representing git object types that can be part of the index file are
221 :class:`~git.objects.tree.Tree and :class:`~git.objects.blob.Blob`. In addition,
222 :class:`~git.objects.submodule.base.Submodule`, which is not really a git object
223 type but can be part of an index file, is also a subclass.
224 """
226 __slots__ = ("path", "mode")
228 # For compatibility with iterable lists.
229 _id_attribute_ = "path"
231 def __init__(
232 self,
233 repo: "Repo",
234 binsha: bytes,
235 mode: Union[None, int] = None,
236 path: Union[None, PathLike] = None,
237 ) -> None:
238 """Initialize a newly instanced :class:`IndexObject`.
240 :param repo:
241 The :class:`~git.repo.base.Repo` we are located in.
243 :param binsha:
244 20 byte sha1.
246 :param mode:
247 The stat-compatible file mode as :class:`int`.
248 Use the :mod:`stat` module to evaluate the information.
250 :param path:
251 The path to the file in the file system, relative to the git repository
252 root, like ``file.ext`` or ``folder/other.ext``.
254 :note:
255 Path may not be set if the index object has been created directly, as it
256 cannot be retrieved without knowing the parent tree.
257 """
258 super().__init__(repo, binsha)
259 if mode is not None:
260 self.mode = mode
261 if path is not None:
262 self.path = path
264 def __hash__(self) -> int:
265 """
266 :return:
267 Hash of our path as index items are uniquely identifiable by path, not by
268 their data!
269 """
270 return hash(self.path)
272 def _set_cache_(self, attr: str) -> None:
273 if attr in IndexObject.__slots__:
274 # They cannot be retrieved later on (not without searching for them).
275 raise AttributeError(
276 "Attribute '%s' unset: path and mode attributes must have been set during %s object creation"
277 % (attr, type(self).__name__)
278 )
279 else:
280 super()._set_cache_(attr)
281 # END handle slot attribute
283 @property
284 def name(self) -> str:
285 """:return: Name portion of the path, effectively being the basename"""
286 return osp.basename(self.path)
288 @property
289 def abspath(self) -> PathLike:
290 R"""
291 :return:
292 Absolute path to this index object in the file system (as opposed to the
293 :attr:`path` field which is a path relative to the git repository).
295 The returned path will be native to the system and contains ``\`` on
296 Windows.
297 """
298 if self.repo.working_tree_dir is not None:
299 return join_path_native(self.repo.working_tree_dir, self.path)
300 else:
301 raise WorkTreeRepositoryUnsupported("working_tree_dir was None or empty")