1
- """This module contains the code allowing to load modules from specific git commits.
2
-
3
- ```python
4
- from griffe.git import load_git
5
-
6
- # where `repo` is the folder *containing* `.git`
7
- old_api = load_git("my_module", commit="v0.1.0", repo="path/to/repo")
8
- ```
9
- """
1
+ """This module contains Git utilities."""
10
2
11
3
from __future__ import annotations
12
4
13
5
import os
14
6
import shutil
15
7
import subprocess
8
+ import warnings
16
9
from contextlib import contextmanager
17
10
from pathlib import Path
18
11
from tempfile import TemporaryDirectory
19
- from typing import TYPE_CHECKING , Any , Iterator , Sequence
12
+ from typing import Any , Iterator
20
13
21
- from griffe import loader
22
14
from griffe .exceptions import GitError
23
15
24
- if TYPE_CHECKING :
25
- from griffe .collections import LinesCollection , ModulesCollection
26
- from griffe .dataclasses import Object
27
- from griffe .enumerations import Parser
28
- from griffe .extensions .base import Extensions
16
+ WORKTREE_PREFIX = "griffe-worktree-"
29
17
30
18
31
- WORKTREE_PREFIX = "griffe-worktree-"
19
+ # TODO: Remove at some point.
20
+ def __getattr__ (name : str ) -> Any :
21
+ if name == "load_git" :
22
+ warnings .warn (
23
+ f"Importing { name } from griffe.git is deprecated. Import it from griffe.loader instead." ,
24
+ DeprecationWarning ,
25
+ stacklevel = 2 ,
26
+ )
27
+
28
+ from griffe .loader import load_git
29
+
30
+ return load_git
31
+ raise AttributeError
32
+
32
33
34
+ def assert_git_repo (path : str | Path ) -> None :
35
+ """Assert that a directory is a Git repository.
33
36
34
- def _assert_git_repo (repo : str | Path ) -> None :
37
+ Parameters:
38
+ path: Path to a directory.
39
+
40
+ Raises:
41
+ OSError: When the directory is not a Git repository.
42
+ """
35
43
if not shutil .which ("git" ):
36
44
raise RuntimeError ("Could not find git executable. Please install git." )
37
45
38
46
try :
39
47
subprocess .run (
40
- ["git" , "-C" , str (repo ), "rev-parse" , "--is-inside-work-tree" ],
48
+ ["git" , "-C" , str (path ), "rev-parse" , "--is-inside-work-tree" ],
41
49
check = True ,
42
50
stdout = subprocess .DEVNULL ,
43
51
stderr = subprocess .DEVNULL ,
44
52
)
45
53
except subprocess .CalledProcessError as err :
46
- raise OSError (f"Not a git repository: { repo } " ) from err
54
+ raise OSError (f"Not a git repository: { path } " ) from err
47
55
48
56
49
- def _get_latest_tag (path : str | Path ) -> str :
50
- if isinstance (path , str ):
51
- path = Path (path )
52
- if not path .is_dir ():
53
- path = path .parent
57
+ def get_latest_tag (repo : str | Path ) -> str :
58
+ """Get latest tag of a Git repository.
59
+
60
+ Parameters:
61
+ repo: The path to Git repository.
62
+
63
+ Returns:
64
+ The latest tag.
65
+ """
66
+ if isinstance (repo , str ):
67
+ repo = Path (repo )
68
+ if not repo .is_dir ():
69
+ repo = repo .parent
54
70
process = subprocess .run (
55
71
["git" , "tag" , "-l" , "--sort=-committerdate" ],
56
- cwd = path ,
72
+ cwd = repo ,
57
73
text = True ,
58
74
stdout = subprocess .PIPE ,
59
75
stderr = subprocess .STDOUT ,
60
76
check = False ,
61
77
)
62
78
output = process .stdout .strip ()
63
79
if process .returncode != 0 or not output :
64
- raise GitError (f"Cannot list Git tags in { path } : { output or 'no tags' } " )
80
+ raise GitError (f"Cannot list Git tags in { repo } : { output or 'no tags' } " )
65
81
return output .split ("\n " , 1 )[0 ]
66
82
67
83
68
- def _get_repo_root (path : str | Path ) -> str :
69
- if isinstance (path , str ):
70
- path = Path (path )
71
- if not path .is_dir ():
72
- path = path .parent
84
+ def get_repo_root (repo : str | Path ) -> str :
85
+ """Get the root of a Git repository.
86
+
87
+ Parameters:
88
+ repo: The path to a Git repository.
89
+
90
+ Returns:
91
+ The root of the repository.
92
+ """
93
+ if isinstance (repo , str ):
94
+ repo = Path (repo )
95
+ if not repo .is_dir ():
96
+ repo = repo .parent
73
97
output = subprocess .check_output (
74
98
["git" , "rev-parse" , "--show-toplevel" ],
75
- cwd = path ,
99
+ cwd = repo ,
76
100
)
77
101
return output .decode ().strip ()
78
102
79
103
80
104
@contextmanager
81
- def _tmp_worktree (repo : str | Path = "." , ref : str = "HEAD" ) -> Iterator [Path ]:
105
+ def tmp_worktree (repo : str | Path = "." , ref : str = "HEAD" ) -> Iterator [Path ]:
82
106
"""Context manager that checks out the given reference in the given repository to a temporary worktree.
83
107
84
108
Parameters:
@@ -92,7 +116,7 @@ def _tmp_worktree(repo: str | Path = ".", ref: str = "HEAD") -> Iterator[Path]:
92
116
OSError: If `repo` is not a valid `.git` repository
93
117
RuntimeError: If the `git` executable is unavailable, or if it cannot create a worktree
94
118
"""
95
- _assert_git_repo (repo )
119
+ assert_git_repo (repo )
96
120
repo_name = Path (repo ).resolve ().name
97
121
with TemporaryDirectory (prefix = f"{ WORKTREE_PREFIX } { repo_name } -{ ref } -" ) as tmp_dir :
98
122
branch = f"griffe_{ ref } "
@@ -113,75 +137,4 @@ def _tmp_worktree(repo: str | Path = ".", ref: str = "HEAD") -> Iterator[Path]:
113
137
subprocess .run (["git" , "-C" , repo , "branch" , "-D" , branch ], stdout = subprocess .DEVNULL , check = False )
114
138
115
139
116
- def load_git (
117
- objspec : str | Path | None = None ,
118
- / ,
119
- * ,
120
- ref : str = "HEAD" ,
121
- repo : str | Path = "." ,
122
- submodules : bool = True ,
123
- extensions : Extensions | None = None ,
124
- search_paths : Sequence [str | Path ] | None = None ,
125
- docstring_parser : Parser | None = None ,
126
- docstring_options : dict [str , Any ] | None = None ,
127
- lines_collection : LinesCollection | None = None ,
128
- modules_collection : ModulesCollection | None = None ,
129
- allow_inspection : bool = True ,
130
- find_stubs_package : bool = False ,
131
- # TODO: Remove at some point.
132
- module : str | Path | None = None ,
133
- ) -> Object :
134
- """Load and return a module from a specific Git reference.
135
-
136
- This function will create a temporary
137
- [git worktree](https://git-scm.com/docs/git-worktree) at the requested reference
138
- before loading `module` with [`griffe.load`][griffe.loader.load].
139
-
140
- This function requires that the `git` executable is installed.
141
-
142
- Parameters:
143
- objspec: The Python path of an object, or file path to a module.
144
- ref: A Git reference such as a commit, tag or branch.
145
- repo: Path to the repository (i.e. the directory *containing* the `.git` directory)
146
- submodules: Whether to recurse on the submodules.
147
- This parameter only makes sense when loading a package (top-level module).
148
- extensions: The extensions to use.
149
- search_paths: The paths to search into (relative to the repository root).
150
- docstring_parser: The docstring parser to use. By default, no parsing is done.
151
- docstring_options: Additional docstring parsing options.
152
- lines_collection: A collection of source code lines.
153
- modules_collection: A collection of modules.
154
- allow_inspection: Whether to allow inspecting modules when visiting them is not possible.
155
- find_stubs_package: Whether to search for stubs-only package.
156
- If both the package and its stubs are found, they'll be merged together.
157
- If only the stubs are found, they'll be used as the package itself.
158
- module: Deprecated. Use `objspec` positional-only parameter instead.
159
-
160
- Returns:
161
- A Griffe object.
162
- """
163
- with _tmp_worktree (repo , ref ) as worktree :
164
- search_paths = [worktree / path for path in search_paths or ["." ]]
165
- if isinstance (objspec , Path ):
166
- objspec = worktree / objspec
167
- # TODO: Remove at some point.
168
- if isinstance (module , Path ):
169
- module = worktree / module
170
- return loader .load (
171
- objspec ,
172
- submodules = submodules ,
173
- try_relative_path = False ,
174
- extensions = extensions ,
175
- search_paths = search_paths ,
176
- docstring_parser = docstring_parser ,
177
- docstring_options = docstring_options ,
178
- lines_collection = lines_collection ,
179
- modules_collection = modules_collection ,
180
- allow_inspection = allow_inspection ,
181
- find_stubs_package = find_stubs_package ,
182
- # TODO: Remove at some point.
183
- module = module ,
184
- )
185
-
186
-
187
- __all__ = ["load_git" ]
140
+ __all__ = ["assert_git_repo" , "get_latest_tag" , "get_repo_root" , "tmp_worktree" ]
0 commit comments