12
12
from quartodoc import Builder , convert_inventory
13
13
from pydantic import BaseModel
14
14
15
+
15
16
def get_package_path (package_name ):
16
17
"""
17
18
Get the path to a package installed in the current environment.
@@ -20,13 +21,16 @@ def get_package_path(package_name):
20
21
lib = importlib .import_module (package_name )
21
22
return lib .__path__ [0 ]
22
23
except ModuleNotFoundError :
23
- raise ModuleNotFoundError (f"Package { package_name } not found. Please install it in your environment." )
24
+ raise ModuleNotFoundError (
25
+ f"Package { package_name } not found. Please install it in your environment."
26
+ )
24
27
25
28
26
29
class FileInfo (BaseModel ):
27
30
size : int
28
31
mtime : float
29
- name : str = ""
32
+ name : str = ""
33
+
30
34
31
35
class QuartoDocFileChangeHandler (PatternMatchingEventHandler ):
32
36
"""
@@ -35,51 +39,59 @@ class QuartoDocFileChangeHandler(PatternMatchingEventHandler):
35
39
36
40
# Ignore patterns for the file watcher that are not relevant to the docs
37
41
py_ignore_patterns = [
38
- '*/__pycache__/*' , # These are the compiled python code files which are automatically generated by Python
39
- '*/.ipynb_checkpoints/*' , # This directory is created by Jupyter Notebook for auto-saving notebooks
40
- '*/.vscode/*' , # If you're using Visual Studio Code, it creates this directory to store settings specific to that project.
41
- '*/.idea/*' , # Similar to .vscode/, but for JetBrains IDEs like PyCharm.
42
- '*/.git/*' , # i This directory is created by Git. It's not relevant to the docs.
43
- '*/venv/*' , '*/env/*' , '*/.env/*' , # Common names for directories containing a Python virtual environment.
44
- '*/.pytest_cache/*' , # This directory is created when you run Pytest.
45
- '*/.eggs/*' , '*/dist/*' , '*/build/*' , '*/*.egg-info/*' , # These are typically created when building Python packages with setuptools.
46
- '*.pyo' , # These are optimized .pyc files, created when Python is run with the -O flag.
47
- '*.pyd' , # This is the equivalent of a .pyc file, but for C extensions on Windows.
48
- '*/.mypy_cache/*' , # This directory is created when you run mypy.
42
+ "*/__pycache__/*" , # These are the compiled python code files which are automatically generated by Python
43
+ "*/.ipynb_checkpoints/*" , # This directory is created by Jupyter Notebook for auto-saving notebooks
44
+ "*/.vscode/*" , # If you're using Visual Studio Code, it creates this directory to store settings specific to that project.
45
+ "*/.idea/*" , # Similar to .vscode/, but for JetBrains IDEs like PyCharm.
46
+ "*/.git/*" , # i This directory is created by Git. It's not relevant to the docs.
47
+ "*/venv/*" ,
48
+ "*/env/*" ,
49
+ "*/.env/*" , # Common names for directories containing a Python virtual environment.
50
+ "*/.pytest_cache/*" , # This directory is created when you run Pytest.
51
+ "*/.eggs/*" ,
52
+ "*/dist/*" ,
53
+ "*/build/*" ,
54
+ "*/*.egg-info/*" , # These are typically created when building Python packages with setuptools.
55
+ "*.pyo" , # These are optimized .pyc files, created when Python is run with the -O flag.
56
+ "*.pyd" , # This is the equivalent of a .pyc file, but for C extensions on Windows.
57
+ "*/.mypy_cache/*" , # This directory is created when you run mypy.
49
58
]
50
59
51
60
def __init__ (self , callback ):
52
- super ().__init__ (ignore_patterns = self .py_ignore_patterns , ignore_directories = True )
61
+ super ().__init__ (
62
+ ignore_patterns = self .py_ignore_patterns , ignore_directories = True
63
+ )
53
64
self .callback = callback
54
65
self .old_file_info = FileInfo (size = - 1 , mtime = - 1 , name = "" )
55
66
56
-
57
- def get_file_info (self , path :str ) -> FileInfo :
67
+ def get_file_info (self , path : str ) -> FileInfo :
58
68
"""
59
69
Get the file size and modification time.
60
70
"""
61
- return FileInfo (size = os . stat ( path ). st_size ,
62
- mtime = os .stat (path ).st_mtime ,
63
- name = path )
64
-
65
- def is_diff (self , old :FileInfo , new :FileInfo ) -> bool :
71
+ return FileInfo (
72
+ size = os . stat ( path ). st_size , mtime = os .stat (path ).st_mtime , name = path
73
+ )
74
+
75
+ def is_diff (self , old : FileInfo , new : FileInfo ) -> bool :
66
76
"""
67
77
Check if a file has changed. Prevents duplicate events from being triggered.
68
78
"""
69
79
same_nm = old .name == new .name
70
80
diff_sz = old .size != new .size
71
- diff_tm = ( new .mtime - old .mtime ) # wait 1/4 second before triggering
81
+ diff_tm = new .mtime - old .mtime # wait 1/4 second before triggering
72
82
73
- if diff_tm < .25 : # if consequetive events are less than 1/4th of a second apart, ignore
83
+ if (
84
+ diff_tm < 0.25
85
+ ): # if consequetive events are less than 1/4th of a second apart, ignore
74
86
return False
75
87
elif same_nm :
76
88
if diff_sz or diff_tm >= 0.25 :
77
89
return True
78
90
else :
79
91
return False
80
92
else :
81
- return True
82
-
93
+ return True
94
+
83
95
def callback_if_diff (self , event ):
84
96
"""
85
97
Call the callback if the file has changed.
@@ -92,14 +104,15 @@ def callback_if_diff(self, event):
92
104
93
105
@classmethod
94
106
def print_event (cls , event ):
95
- print (f' Rebuilding docs. Detected: { event .event_type } path : { event .src_path } ' )
107
+ print (f" Rebuilding docs. Detected: { event .event_type } path : { event .src_path } " )
96
108
97
109
def on_modified (self , event ):
98
110
self .callback_if_diff (event )
99
111
100
112
def on_created (self , event ):
101
113
self .callback_if_diff (event )
102
114
115
+
103
116
def _enable_logs ():
104
117
import logging
105
118
import sys
@@ -132,10 +145,29 @@ def cli():
132
145
133
146
134
147
@click .command ()
135
- @click .option ("--config" , default = "_quarto.yml" , help = "Change the path to the configuration file. The default is `./_quarto.yml`" )
136
- @click .option ("--filter" , nargs = 1 , default = "*" , help = "Specify the filter to select specific files. The default is '*' which selects all files." )
137
- @click .option ("--dry-run" , is_flag = True , default = False , help = "If set, prevents new documents from being generated." )
138
- @click .option ("--watch" , is_flag = True , default = False , help = "If set, the command will keep running and watch for changes in the package directory." )
148
+ @click .option (
149
+ "--config" ,
150
+ default = "_quarto.yml" ,
151
+ help = "Change the path to the configuration file. The default is `./_quarto.yml`" ,
152
+ )
153
+ @click .option (
154
+ "--filter" ,
155
+ nargs = 1 ,
156
+ default = "*" ,
157
+ help = "Specify the filter to select specific files. The default is '*' which selects all files." ,
158
+ )
159
+ @click .option (
160
+ "--dry-run" ,
161
+ is_flag = True ,
162
+ default = False ,
163
+ help = "If set, prevents new documents from being generated." ,
164
+ )
165
+ @click .option (
166
+ "--watch" ,
167
+ is_flag = True ,
168
+ default = False ,
169
+ help = "If set, the command will keep running and watch for changes in the package directory." ,
170
+ )
139
171
@click .option ("--verbose" , is_flag = True , default = False , help = "Enable verbose logging." )
140
172
def build (config , filter , dry_run , watch , verbose ):
141
173
"""
@@ -160,7 +192,7 @@ def build(config, filter, dry_run, watch, verbose):
160
192
pkg_path = get_package_path (builder .package )
161
193
print (f"Watching { pkg_path } for changes..." )
162
194
observer = Observer ()
163
- observer ._event_queue .maxsize = 1 # the default is 0 which is infinite, and there isn't a way to set this in the constructor
195
+ observer ._event_queue .maxsize = 1 # the default is 0 which is infinite, and there isn't a way to set this in the constructor
164
196
event_handler = QuartoDocFileChangeHandler (callback = doc_build )
165
197
observer .schedule (event_handler , pkg_path , recursive = True )
166
198
observer .schedule (event_handler , cfg_path , recursive = True )
@@ -173,9 +205,10 @@ def build(config, filter, dry_run, watch, verbose):
173
205
finally :
174
206
observer .stop ()
175
207
observer .join ()
176
- else :
208
+ else :
177
209
doc_build ()
178
210
211
+
179
212
@click .command ()
180
213
@click .argument ("config" , default = "_quarto.yml" )
181
214
@click .option ("--dry-run" , is_flag = True , default = False )
@@ -192,7 +225,6 @@ def interlinks(config, dry_run):
192
225
return
193
226
194
227
for k , v in interlinks ["sources" ].items ():
195
-
196
228
# TODO: user shouldn't need to include their own docs in interlinks
197
229
if v ["url" ] == "/" :
198
230
continue
0 commit comments