Skip to content

Commit

Permalink
Merge pull request #889 from sphinx-contrib/use-pathlib-part2
Browse files Browse the repository at this point in the history
Use pathlib (Part 2)
  • Loading branch information
jdknight authored Feb 27, 2024
2 parents 01b91a5 + 6f4902d commit 7106029
Show file tree
Hide file tree
Showing 20 changed files with 139 additions and 124 deletions.
3 changes: 2 additions & 1 deletion sphinxcontrib/confluencebuilder/__main__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: BSD-2-Clause
# Copyright Sphinx Confluence Builder Contributors (AUTHORS)

from pathlib import Path
from sphinx.util.console import color_terminal
from sphinx.util.console import nocolor # pylint: disable=no-name-in-module
from sphinxcontrib.confluencebuilder import __version__ as version
Expand Down Expand Up @@ -29,7 +30,7 @@ def main():
parser.add_argument('--verbose', '-V', action='count', default=0)
parser.add_argument('--version', action='version',
version='%(prog)s ' + version)
parser.add_argument('--work-dir')
parser.add_argument('--work-dir', type=Path)

args, _ = parser.parse_known_args()
if args.help:
Expand Down
33 changes: 17 additions & 16 deletions sphinxcontrib/confluencebuilder/assets.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# Copyright Sphinx Confluence Builder Contributors (AUTHORS)

from docutils import nodes
from pathlib import Path
from sphinx import addnodes
from sphinx.util.osutil import canon_path
from sphinx.util.images import guess_mimetype
Expand All @@ -11,7 +12,6 @@
from sphinxcontrib.confluencebuilder.std.confluence import SUPPORTED_IMAGE_TYPES
from sphinxcontrib.confluencebuilder.util import ConfluenceUtil
from sphinxcontrib.confluencebuilder.util import find_env_abspath
import os

# default content type to use if a type cannot be detected for an asset
DEFAULT_CONTENT_TYPE = 'application/octet-stream'
Expand Down Expand Up @@ -54,15 +54,15 @@ class ConfluenceAssetManager:
Args:
config: the active configuration
env: the build environment
outdir: configured output directory (where assets may be stored)
out_dir: configured output directory (where assets may be stored)
"""
def __init__(self, config, env, outdir):
def __init__(self, config, env, out_dir):
self.assets = []
self.env = env
self.force_standalone = config.confluence_asset_force_standalone
self.hash2asset = {}
self.keys = set()
self.outdir = outdir
self.out_dir = out_dir
self.path2asset = {}
self.root_doc = config.root_doc

Expand All @@ -83,8 +83,8 @@ def add(self, path, docname):
the key, document name and path
"""
logger.verbose('adding manual attachment: %s' % path)
abspath = find_env_abspath(self.env, self.outdir, path)
return self._handle_entry(abspath, docname, standalone=True)
abs_path = find_env_abspath(self.env, self.out_dir, path)
return self._handle_entry(abs_path, docname, standalone=True)

def build(self):
"""
Expand Down Expand Up @@ -274,7 +274,8 @@ def _handle_entry(self, path, docname, standalone=False):

if path not in self.path2asset:
hash_ = ConfluenceUtil.hash_asset(path)
type_ = guess_mimetype(path, default=DEFAULT_CONTENT_TYPE)
# str-cast for sphinx-6.1
type_ = guess_mimetype(str(path), default=DEFAULT_CONTENT_TYPE)
else:
hash_ = self.path2asset[path].hash
type_ = self.path2asset[path].type
Expand All @@ -284,18 +285,18 @@ def _handle_entry(self, path, docname, standalone=False):
hash_exists = hash_ in self.hash2asset
if not hash_exists or standalone:
# no asset entry and no hash entry (or standalone); new asset
key = os.path.basename(path)
key = path.name

# Confluence does not allow attachments with select characters.
# Filter out the asset name to a compatible key value.
for rep in INVALID_CHARS:
key = key.replace(rep, '_')

filename, file_ext = os.path.splitext(key)
new_path = Path(key)
idx = 1
while key in self.keys:
idx += 1
key = f'{filename}_{idx}{file_ext}'
key = f'{new_path.stem}_{idx}{new_path.suffix}'
self.keys.add(key)

asset = ConfluenceAsset(key, path, type_, hash_)
Expand Down Expand Up @@ -332,20 +333,20 @@ def _interpret_asset_path(self, node):
path = None
if isinstance(node, nodes.image):
# uri's will be relative to documentation root.
path = str(node['uri'])
path = Path(node['uri'])
elif isinstance(node, addnodes.download_reference):
# reftarget will be a reference to the asset with respect to the
# document (refdoc) holding this reference. Use reftarget and refdoc
# to find a proper path.
docdir = os.path.dirname(node['refdoc'])
path = os.path.join(docdir, node['reftarget'])
docdir = Path(node['refdoc']).parent
path = docdir / node['reftarget']

abspath = find_env_abspath(self.env, self.outdir, path)
abs_path = find_env_abspath(self.env, self.out_dir, path)

if not abspath:
if not abs_path:
logger.verbose('failed to find path: %s' % path)

return abspath
return abs_path


class ConfluenceSupportedImages:
Expand Down
19 changes: 9 additions & 10 deletions sphinxcontrib/confluencebuilder/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
from docutils import nodes
from docutils.io import StringOutput
from pathlib import Path
from os import path
from sphinx import addnodes
from sphinx import version_info as sphinx_version_info
from sphinx.builders import Builder
Expand Down Expand Up @@ -152,7 +151,7 @@ def init(self):
if new_url:
self.cloud = new_url.endswith('.atlassian.net/wiki/')

self.assets = ConfluenceAssetManager(config, self.env, self.outdir)
self.assets = ConfluenceAssetManager(config, self.env, self.out_dir)
self.writer = ConfluenceWriter(self)
self.config.sphinx_verbosity = self._verbose
self.publisher.init(self.config, self.cloud)
Expand Down Expand Up @@ -789,13 +788,13 @@ def to_asset_name(asset):
for asset in status_iterator(assets, 'publishing assets... ',
length=len(assets), verbosity=self._verbose,
stringify_func=to_asset_name):
key, absfile, type_, hash_, docname = asset
key, abs_file, type_, hash_, docname = asset
if self._check_publish_skip(docname):
self.verbose(key + ' skipped due to configuration')
continue

try:
with open(absfile, 'rb') as file:
with abs_file.open('rb') as file:
output = file.read()
self.publish_asset(key, docname, output, type_, hash_)
except OSError as err:
Expand Down Expand Up @@ -910,13 +909,13 @@ def _generate_special_document(self, docname, generator):
header_template_data = ''

if self.config.confluence_header_file is not None:
fname = path.join(self.env.srcdir,
header_file = Path(self.env.srcdir,
self.config.confluence_header_file)
try:
with open(fname, encoding='utf-8') as file:
with header_file.open(encoding='utf-8') as file:
header_template_data = file.read() + '\n'
except OSError as err:
self.warn(f'error reading file {fname}: {err}')
self.warn(f'error reading file {header_file}: {err}')

# if no data is supplied, the file is plain text
if self.config.confluence_header_data is None:
Expand All @@ -932,13 +931,13 @@ def _generate_special_document(self, docname, generator):
footer_template_data = ''

if self.config.confluence_footer_file is not None:
fname = path.join(self.env.srcdir,
footer_file = Path(self.env.srcdir,
self.config.confluence_footer_file)
try:
with open(fname, encoding='utf-8') as file:
with footer_file.open(encoding='utf-8') as file:
footer_template_data = file.read() + '\n'
except OSError as err:
self.warn(f'error reading file {fname}: {err}')
self.warn(f'error reading file {footer_file}: {err}')

# if no data is supplied, the file is plain text
if self.config.confluence_footer_data is None:
Expand Down
10 changes: 5 additions & 5 deletions sphinxcontrib/confluencebuilder/cmd/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
# Copyright Sphinx Confluence Builder Contributors (AUTHORS)

from contextlib import suppress
from pathlib import Path
from sphinx.application import Sphinx
from sphinx.util.docutils import docutils_namespace
from sphinxcontrib.confluencebuilder.logger import ConfluenceLogger as logger
import os
import sys

#: default builder to invoke when one is not specified
Expand All @@ -26,7 +26,7 @@ def build_main(args_parser):
"""

args_parser.add_argument('-D', action='append', default=[], dest='define')
args_parser.add_argument('--output-dir', '-o')
args_parser.add_argument('--output-dir', '-o', type=Path)

known_args = sys.argv[1:]
args, unknown_args = args_parser.parse_known_args(known_args)
Expand All @@ -42,12 +42,12 @@ def build_main(args_parser):
logger.error('invalid define provided in command line')
return 1

work_dir = args.work_dir if args.work_dir else os.getcwd()
work_dir = args.work_dir if args.work_dir else Path.cwd()
if args.output_dir:
output_dir = args.output_dir
else:
output_dir = os.path.join(work_dir, '_build', 'confluence')
doctrees_dir = os.path.join(output_dir, '.doctrees')
output_dir = work_dir / '_build' / 'confluence'
doctrees_dir = output_dir / '.doctrees'
builder = args.action if args.action else DEFAULT_BUILDER

verbosity = 0
Expand Down
14 changes: 7 additions & 7 deletions sphinxcontrib/confluencebuilder/cmd/report.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from collections import OrderedDict
from docutils import __version__ as docutils_version
from pathlib import Path
from requests import __version__ as requests_version
from sphinx import __version__ as sphinx_version
from sphinx.application import Sphinx
Expand All @@ -19,7 +20,6 @@
from urllib.parse import urlparse
from urllib3 import __version__ as urllib3_version
from xml.etree import ElementTree
import os
import platform
import sys
import traceback
Expand Down Expand Up @@ -68,7 +68,7 @@ def report_main(args_parser):

rv = 0
offline = args.offline
work_dir = args.work_dir if args.work_dir else os.getcwd()
work_dir = args.work_dir if args.work_dir else Path.cwd()

# setup sphinx engine to extract configuration
config = {}
Expand All @@ -81,10 +81,10 @@ def report_main(args_parser):
print('fetching configuration information...')
builder = ConfluenceReportBuilder.name
app = Sphinx(
work_dir, # document sources
work_dir, # directory with configuration
tmp_dir, # output for built documents
tmp_dir, # output for doctree files
str(work_dir), # document sources
str(work_dir), # directory with configuration
str(tmp_dir), # output for built documents
str(tmp_dir), # output for doctree files
builder, # builder to execute
status=sys.stdout, # sphinx status output
warning=sys.stderr) # sphinx warning output
Expand Down Expand Up @@ -126,7 +126,7 @@ def report_main(args_parser):
sys.stdout.flush()
tb_msg = traceback.format_exc()
logger.error(tb_msg)
if os.path.isfile(os.path.join(work_dir, 'conf.py')):
if Path(work_dir / 'conf.py').is_file():
configuration_load_issue = 'unable to load configuration'
configuration_load_issue += '\n\n' + tb_msg.strip()
else:
Expand Down
14 changes: 7 additions & 7 deletions sphinxcontrib/confluencebuilder/cmd/wipe.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
# SPDX-License-Identifier: BSD-2-Clause
# Copyright Sphinx Confluence Builder Contributors (AUTHORS)

from pathlib import Path
from sphinx.application import Sphinx
from sphinx.locale import __
from sphinx.util.docutils import docutils_namespace
from sphinxcontrib.confluencebuilder.config import process_ask_configs
from sphinxcontrib.confluencebuilder.logger import ConfluenceLogger as logger
from sphinxcontrib.confluencebuilder.publisher import ConfluencePublisher
from sphinxcontrib.confluencebuilder.util import temp_dir
import os
import sys
import traceback

Expand All @@ -34,7 +34,7 @@ def wipe_main(args_parser):
if unknown_args:
logger.warn('unknown arguments: {}'.format(' '.join(unknown_args)))

work_dir = args.work_dir if args.work_dir else os.getcwd()
work_dir = args.work_dir if args.work_dir else Path.cwd()

# protection warning
if not args.danger:
Expand Down Expand Up @@ -63,10 +63,10 @@ def wipe_main(args_parser):
try:
with temp_dir() as tmp_dir, docutils_namespace():
app = Sphinx(
work_dir, # document sources
work_dir, # directory with configuration
tmp_dir, # output for built documents
tmp_dir, # output for doctree files
str(work_dir), # document sources
str(work_dir), # directory with configuration
str(tmp_dir), # output for built documents
str(tmp_dir), # output for doctree files
'confluence', # builder to execute
status=sys.stdout, # sphinx status output
warning=sys.stderr) # sphinx warning output
Expand All @@ -86,7 +86,7 @@ def wipe_main(args_parser):
except Exception: # noqa: BLE001
sys.stdout.flush()
logger.error(traceback.format_exc())
if os.path.isfile(os.path.join(work_dir, 'conf.py')):
if Path(work_dir / 'conf.py').is_file():
logger.error('unable to load configuration')
else:
logger.error('no documentation/missing configuration')
Expand Down
3 changes: 2 additions & 1 deletion sphinxcontrib/confluencebuilder/config/checks.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: BSD-2-Clause
# Copyright Sphinx Confluence Builder Contributors (AUTHORS)

from pathlib import Path
from sphinxcontrib.confluencebuilder.config.notifications import deprecated
from sphinxcontrib.confluencebuilder.config.notifications import warnings
from sphinxcontrib.confluencebuilder.config.validation import ConfigurationValidation
Expand Down Expand Up @@ -170,7 +171,7 @@ def validate_configuration(builder):
''')

for cert in cert_files:
if cert and not os.path.isfile(os.path.join(env.srcdir, cert)):
if cert and not Path(env.srcdir, cert).is_file():
raise ConfluenceConfigurationError('''\
confluence_client_cert missing certificate file
Expand Down
16 changes: 8 additions & 8 deletions sphinxcontrib/confluencebuilder/config/defaults.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# SPDX-License-Identifier: BSD-2-Clause
# Copyright Sphinx Confluence Builder Contributors (AUTHORS)

from pathlib import Path
from sphinxcontrib.confluencebuilder.debug import PublishDebug
from sphinxcontrib.confluencebuilder.util import str2bool
import os


# configures the default editor to publication
Expand Down Expand Up @@ -43,13 +43,13 @@ def apply_defaults(builder):
if conf.confluence_adv_restricted is None:
conf.confluence_adv_restricted = []

if conf.confluence_ca_cert and not os.path.isabs(conf.confluence_ca_cert):
# if the ca path is not an absolute path, the path is a relative
# path based on the source directory (i.e. passed configuration
# checks); resolve the file here before it eventually gets provided
# to Requests
conf.confluence_ca_cert = os.path.join(
env.srcdir, conf.confluence_ca_cert)
if conf.confluence_ca_cert:
if not Path(conf.confluence_ca_cert).is_absolute():
# if the ca path is not an absolute path, the path is a relative
# path based on the source directory (i.e. passed configuration
# checks); resolve the file here before it eventually gets provided
# to Requests
conf.confluence_ca_cert = Path(env.srcdir, conf.confluence_ca_cert)

if conf.confluence_cleanup_search_mode is None:
# the default is `search`, since on Confluence Server/DC; the `direct`
Expand Down
2 changes: 1 addition & 1 deletion sphinxcontrib/confluencebuilder/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ def track_page_hash(self, docname):
return doc_hash

# determine the hash of the document based on data + config-hash
src_file = self.env.doc2path(docname)
src_file = Path(self.env.doc2path(docname))
src_file_hash = ConfluenceUtil.hash_asset(src_file)
doc_hash_data = self._active_hash + src_file_hash
doc_hash = ConfluenceUtil.hash(doc_hash_data)
Expand Down
4 changes: 3 additions & 1 deletion sphinxcontrib/confluencebuilder/logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from collections import deque
from contextlib import suppress
from pathlib import Path
from sphinx.util import logging
from sphinx.util.console import bold # pylint: disable=no-name-in-module
import sys
Expand Down Expand Up @@ -118,7 +119,8 @@ def trace(container, data):
This is solely for manually debugging unexpected scenarios.
"""
try:
with open('trace.log', 'a', encoding='utf-8') as file:
trace_file = Path('trace.log')
with trace_file.open('a', encoding='utf-8') as file:
file.write('[%s]\n' % container)
file.write(data)
file.write('\n')
Expand Down
Loading

0 comments on commit 7106029

Please sign in to comment.