Skip to content

Commit ff2c3e9

Browse files
committed
Better default locations for downloads and for searching for pandoc binary
The default download path is now set to a platform specific path: * ~/bin on Linux * ~\AppData\Local\Pandoc on windows (also the default install location for pandoc) * ~/Applications/pandoc on Mac OS X In addition to these paths we also look into ~/.bin on linux and the python script/bin path. The last ensures that pandoc can be installed into a virtual env and is found even if the env is not activated (only run a python directly from that path). Together these changes ensure that * conda packages can be created for pandoc and these pandoc installs are found. * even if a default pandoc install wasn't added to the PATH on windows, it will be found. * On all platforms, we have a proper default install location if a user will use `pypandoc.pandoc_download.download_pandoc()`
1 parent e1113fc commit ff2c3e9

File tree

3 files changed

+60
-11
lines changed

3 files changed

+60
-11
lines changed

‎pypandoc/__init__.py‎

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,13 @@
99

1010
from .py3compat import string_types, cast_bytes, cast_unicode
1111

12+
from pypandoc.pandoc_download import DEFAULT_TARGET_FOLDER, download_pandoc
13+
1214
__author__ = u'Juho Vepsäläinen'
1315
__version__ = '1.1.3'
1416
__license__ = 'MIT'
15-
__all__ = ['convert', 'get_pandoc_formats', 'get_pandoc_version', 'get_pandoc_path']
17+
__all__ = ['convert', 'get_pandoc_formats', 'get_pandoc_version',
18+
'get_pandoc_path', 'download_pandoc']
1619

1720

1821
def convert(source, to, format=None, extra_args=(), encoding='utf-8',
@@ -262,7 +265,8 @@ def get_pandoc_path():
262265
to be callable (i.e. we could get version information from `pandoc --version`).
263266
If `PYPANDOC_PANDOC` is set and valid, it will return that value. If the environment
264267
variable is not set, either the full path to the included pandoc or the pandoc in
265-
`PATH` (whatever is the higher version) will be returned.
268+
`PATH` or a pandoc in some of the more usual (platform specific) install locations
269+
(whatever is the higher version) will be returned.
266270
267271
If a cached path is found, it will return the cached path and stop probing Pandoc
268272
(unless :func:`clean_pandocpath_cache()` is called).
@@ -280,12 +284,32 @@ def _ensure_pandoc_path():
280284
included_pandoc = os.path.join(os.path.dirname(os.path.realpath(__file__)),
281285
"files", "pandoc")
282286
search_paths = ["pandoc", included_pandoc]
287+
pf = "linux" if sys.platform.startswith("linux") else sys.platform
288+
try:
289+
search_paths.append(os.path.join(DEFAULT_TARGET_FOLDER[pf], "pandoc"))
290+
except:
291+
# not one of the know platforms...
292+
pass
293+
if pf == "linux":
294+
# Currently we install into ~/bin, but this is equally likely...
295+
search_paths.append("~/.bin/pandoc")
296+
# Also add the interpreter script path, as that's where pandoc could be
297+
# installed if it's an environment and the environment wasn't activated
298+
if pf == "win32":
299+
search_paths.append(os.path.join(sys.exec_prefix, "Scripts"))
300+
# on windows, Library\bin could also be used, but that's already in
301+
# path by the interpreter!
302+
else:
303+
search_paths.append(os.path.join(sys.exec_prefix, "bin"))
283304
# If a user added the complete path to pandoc to an env, use that as the
284305
# only way to get pandoc so that a user can overwrite even a higher
285306
# version in some other places.
286307
if os.getenv('PYPANDOC_PANDOC', None):
287308
search_paths = [os.getenv('PYPANDOC_PANDOC')]
288309
for path in search_paths:
310+
# Needed for windows and subprocess which can't expand it on it's
311+
# own...
312+
path = os.path.expanduser(path)
289313
curr_version = [0, 0, 0]
290314
version_string = "0.0.0"
291315
try:
@@ -334,7 +358,8 @@ def _ensure_pandoc_path():
334358
335359
"""))
336360
raise OSError("No pandoc was found: either install pandoc and add it\n"
337-
"to your PATH or install pypandoc wheels with included pandoc.")
361+
"to your PATH or or call pypandoc.download_pandoc(...) or\n"
362+
"install pypandoc wheels with included pandoc.")
338363

339364

340365
# -----------------------------------------------------------------------------

‎pypandoc/pandoc_download.py‎

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@
2323
"darwin": "https://github.com/jgm/pandoc/releases/download/1.16.0.2/pandoc-1.16.0.2-osx.pkg"
2424
}
2525

26+
DEFAULT_TARGET_FOLDER = {
27+
"win32": "~\\AppData\\Local\\Pandoc",
28+
"linux": "~/bin",
29+
"darwin": "~/Applications/pandoc"
30+
}
31+
2632

2733
def _handle_linux(filename, targetfolder):
2834

@@ -45,7 +51,7 @@ def _handle_linux(filename, targetfolder):
4551
print("* Copying %s to %s ..." % (exe, targetfolder))
4652
shutil.copyfile(src, dst)
4753
src = os.path.join(tempfolder, "usr", "share", "doc", "pandoc", "copyright")
48-
dst = os.path.join(targetfolder, "copyright")
54+
dst = os.path.join(targetfolder, "copyright.pandoc")
4955
print("* Copying copyright to %s ..." % (targetfolder))
5056
shutil.copyfile(src, dst)
5157
finally:
@@ -102,17 +108,33 @@ def _handle_win32(filename, targetfolder):
102108

103109

104110
def download_pandoc(url=None, targetfolder=None):
111+
"""Download and unpack pandoc
112+
113+
Downloads prebuild binaries for pandoc from `url` and unpacks it into
114+
`targetfolder`.
115+
116+
:param str url: URL for the to be downloaded pandoc binary distribution for
117+
the platform under which this python runs. If no `url` is give, uses
118+
the latest available release at the time pypandoc was released.
119+
120+
:param str targetfolder: directory, where the binaries should be installed
121+
to. If no `targetfolder` is give, uses a platform specific user
122+
location: `~/bin` on Linux, `~/Applications/pandoc` on Mac OS X, and
123+
`~\\AppData\\Local\\Pandoc` on Windows.
124+
"""
105125
pf = sys.platform
126+
106127
# compatibility with py3
107128
if pf.startswith("linux"):
108129
pf = "linux"
109-
assert platform.architecture()[0] == "64bit", "Linux pandoc is only compiled for 64bit."
130+
if platform.architecture()[0] != "64bit":
131+
raise RuntimeError("Linux pandoc is only compiled for 64bit.")
132+
133+
if pf not in PANDOC_URLS:
134+
raise RuntimeError("Can't handle your platform (only Linux, Mac OS X, Windows).")
110135

111136
if url is None:
112-
try:
113-
url = PANDOC_URLS[pf]
114-
except:
115-
raise Exception("No prebuilt pandoc available or not yet implemented for your platform")
137+
url = PANDOC_URLS[pf]
116138

117139
filename = url.split("/")[-1]
118140
if os.path.isfile(filename):
@@ -123,8 +145,10 @@ def download_pandoc(url=None, targetfolder=None):
123145
response = urlopen(url)
124146
with open(filename, 'wb') as out_file:
125147
shutil.copyfileobj(response, out_file)
148+
126149
if targetfolder is None:
127-
targetfolder = os.path.join(os.path.dirname(os.path.realpath(__file__)), "pypandoc", "files")
150+
targetfolder = DEFAULT_TARGET_FOLDER[pf]
151+
targetfolder = os.path.expanduser(targetfolder)
128152

129153
# Make sure target folder exists...
130154
try:

‎setup.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
try:
1616
long_description = pypandoc.convert('README.md', 'rst')
1717
long_description = long_description.replace("\r","")
18-
except OSError:
18+
except OSError as e:
1919
print("\n\n!!! pandoc not found, long_description is bad, don't upload this to PyPI !!!\n\n")
2020
import io
2121
# pandoc is not installed, fallback to using raw contents

0 commit comments

Comments
 (0)