Skip to content

Commit

Permalink
Merge branch 'master' into 2024-maintenance
Browse files Browse the repository at this point in the history
  • Loading branch information
tristanlatr committed Sep 13, 2024
2 parents df769b8 + cf5730f commit 207790e
Show file tree
Hide file tree
Showing 8 changed files with 61 additions and 8 deletions.
2 changes: 2 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ in development
* Trigger a warning when several docstrings are detected for the same object.
* Improve typing.
* Replace the deprecated dependency appdirs with platformdirs.
* Fix WinError caused by the failure of the symlink creation process.
Pydoctor should now run on windows without the need to be administrator.

pydoctor 24.3.3
^^^^^^^^^^^^^^^
Expand Down
2 changes: 2 additions & 0 deletions pydoctor/driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@ def make(system: model.System) -> None:
if not options.htmlsummarypages:
subjects = system.rootobjects
writer.writeIndividualFiles(subjects)
if not options.htmlsubjects:
writer.writeLinks(system)

if options.makeintersphinx:
if not options.makehtml:
Expand Down
4 changes: 4 additions & 0 deletions pydoctor/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,9 @@ def get_parser() -> ArgumentParser:
parser.add_argument(
'--mod-member-order', dest='mod_member_order', default="alphabetical", choices=["alphabetical", "source"],
help=("Presentation order of module/package members. (default: alphabetical)"))
parser.add_argument(
'--use-hardlinks', default=False, action='store_true', dest='use_hardlinks',
help=("Always copy files instead of creating a symlink (hardlinks will be automatically used if the symlink process failed)."))

parser.add_argument('-V', '--version', action='version', version=f'%(prog)s {__version__}')

Expand Down Expand Up @@ -375,6 +378,7 @@ class Options:
nosidebar: int = attr.ib()
cls_member_order: 'Literal["alphabetical", "source"]' = attr.ib()
mod_member_order: 'Literal["alphabetical", "source"]' = attr.ib()
use_hardlinks: bool = attr.ib()

def __attrs_post_init__(self) -> None:
# do some validations...
Expand Down
7 changes: 6 additions & 1 deletion pydoctor/templatewriter/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,12 @@ def writeSummaryPages(self, system: System) -> None:

def writeIndividualFiles(self, obs: Iterable[Documentable]) -> None:
"""
Called last.
Called third.
"""

def writeLinks(self, system: System) -> None:
"""
Called after writeIndividualFiles when option --html-subject is not used.
"""

class Template(abc.ABC):
Expand Down
21 changes: 14 additions & 7 deletions pydoctor/templatewriter/writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import itertools
from pathlib import Path
import shutil
from typing import IO, Iterable, Type, TYPE_CHECKING

from pydoctor import model
Expand Down Expand Up @@ -97,18 +98,24 @@ def writeSummaryPages(self, system: model.System) -> None:
T = time.time()
search.write_lunr_index(self.build_directory, system=system)
system.msg('html', "took %fs"%(time.time() - T), wantsnl=False)


def writeLinks(self, system: model.System) -> None:
if len(system.root_names) == 1:
# If there is just a single root module it is written to index.html to produce nicer URLs.
# To not break old links we also create a symlink from the full module name to the index.html
# To not break old links we also create a link from the full module name to the index.html
# file. This is also good for consistency: every module is accessible by <full module name>.html
root_module_path = (self.build_directory / (list(system.root_names)[0] + '.html'))
root_module_path.unlink(missing_ok=True) # introduced in Python 3.8

try:
root_module_path.unlink()
# not using missing_ok=True because that was only added in Python 3.8 and we still support Python 3.6
except FileNotFoundError:
pass
root_module_path.symlink_to('index.html')
if system.options.use_hardlinks:
# The use wants only harlinks, so simulate an OSError
# to jump directly to the hardlink part.
raise OSError()
root_module_path.symlink_to('index.html')
except (OSError, NotImplementedError): # symlink is not implemented for windows on pypy :/
hardlink_path = (self.build_directory / 'index.html')
shutil.copy(hardlink_path, root_module_path)

def _writeDocsFor(self, ob: model.Documentable) -> None:
if not ob.isVisible:
Expand Down
5 changes: 5 additions & 0 deletions pydoctor/test/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ def writeSummaryPages(self, system: model.System) -> None:
Rig the system to not created the inter sphinx inventory.
"""
system.options.makeintersphinx = False

def writeLinks(self, system: model.System) -> None:
"""
Does nothing.
"""

def _writeDocsFor(self, ob: model.Documentable) -> None:
"""
Expand Down
27 changes: 27 additions & 0 deletions pydoctor/test/test_commandline.py
Original file line number Diff line number Diff line change
Expand Up @@ -272,3 +272,30 @@ def test_make_intersphix(tmp_path: Path) -> None:
assert [p.name for p in tmp_path.iterdir()] == ['objects.inv']
assert inventory.is_file()
assert b'Project: acme-lib\n# Version: 20.12.0-dev123\n' in inventory.read_bytes()

def test_index_symlink(tmp_path: Path) -> None:
"""
Test that the default behaviour is to create symlinks, at least on unix.
For windows users, this has not been a success, so we automatically fallback to copying the file now.
See https://github.com/twisted/pydoctor/issues/808, https://github.com/twisted/pydoctor/issues/720.
"""
import platform
exit_code = driver.main(args=['--html-output', str(tmp_path), 'pydoctor/test/testpackages/basic/'])
assert exit_code == 0
link = (tmp_path / 'basic.html')
assert link.exists()
if platform.system() == 'Windows':
assert link.is_symlink() or link.is_file()
else:
assert link.is_symlink()

def test_index_hardlink(tmp_path: Path) -> None:
"""
Test for option --use-hardlink wich enforce the usage of harlinks.
"""
exit_code = driver.main(args=['--use-hardlink', '--html-output', str(tmp_path), 'pydoctor/test/testpackages/basic/'])
assert exit_code == 0
assert (tmp_path / 'basic.html').exists()
assert not (tmp_path / 'basic.html').is_symlink()
assert (tmp_path / 'basic.html').is_file()
1 change: 1 addition & 0 deletions pydoctor/test/test_templatewriter.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ def test_basic_package(tmp_path: Path) -> None:
root, = system.rootobjects
w._writeDocsFor(root)
w.writeSummaryPages(system)
w.writeLinks(system)
for ob in system.allobjects.values():
url = ob.url
if '#' in url:
Expand Down

0 comments on commit 207790e

Please sign in to comment.