Ответ 1
Модуль urlparse предоставляет путь от URI:
import os, urlparse
p = urlparse.urlparse('file://C:/test/doc.txt')
finalPath = os.path.abspath(os.path.join(p.netloc, p.path))
Подсистема, на которую я не могу контролировать, настаивает на предоставлении путей файловой системы в виде uri. Есть ли модуль/функция python, который может преобразовать этот путь в соответствующую форму, ожидаемую файловой системой, независимо от платформы?
Модуль urlparse предоставляет путь от URI:
import os, urlparse
p = urlparse.urlparse('file://C:/test/doc.txt')
finalPath = os.path.abspath(os.path.join(p.netloc, p.path))
Для будущих читателей. Решение от @Jakob Bowyer не конвертирует URL-адреса в ascii. После небольшого рытья я нашел это решение:
>>> import urllib, urlparse
>>> urllib.url2pathname(urlparse.urlparse('file:///home/user/some%20file.txt').path)
'/home/user/some file.txt'
EDIT:
Вот что я в итоге использовал:
>>> import urllib
>>> urllib.unquote('file:///home/user/some%20file.txt')[7:]
'/home/user/some file.txt'
Чтобы преобразовать файл uri в путь с python (конкретно для 3, я могу сделать для python 2, если кто-то действительно этого хочет):
urllib.parse.urlparse
Скомментируйте компонент пути проанализированного URI с помощью urllib.parse.unquote
тогда...
а. Если путь является оконным путем и начинается с /
: уберите первый символ компонента пути без кавычек (компонент пути в file:///C:/some/file.txt
равен /C:/some/file.txt
, который не интерпретируется как эквивалентный C:\some\file.txt
pathlib.PureWindowsPath
)
б. В противном случае просто используйте компонент пути без кавычек как есть.
Вот функция, которая делает это:
import urllib
import pathlib
def file_uri_to_path(file_uri, path_class=pathlib.PurePath):
"""
This function returns a pathlib.PurePath object for the supplied file URI.
:param str file_uri: The file URI ...
:param class path_class: The type of path in the file_uri. By default it uses
the system specific path pathlib.PurePath, to force a specific type of path
pass pathlib.PureWindowsPath or pathlib.PurePosixPath
:returns: the pathlib.PurePath object
:rtype: pathlib.PurePath
"""
windows_path = isinstance(path_class(),pathlib.PureWindowsPath)
file_uri_parsed = urllib.parse.urlparse(file_uri)
file_uri_path_unquoted = urllib.parse.unquote(file_uri_parsed.path)
if windows_path and file_uri_path_unquoted.startswith("/"):
result = path_class(file_uri_path_unquoted[1:])
else:
result = path_class(file_uri_path_unquoted)
if result.is_absolute() == False:
raise ValueError("Invalid file uri {} : resulting path {} not absolute".format(
file_uri, result))
return result
Примеры использования (работали в Linux):
>>> file_uri_to_path("file:///etc/hosts")
PurePosixPath('/etc/hosts')
>>> file_uri_to_path("file:///etc/hosts", pathlib.PurePosixPath)
PurePosixPath('/etc/hosts')
>>> file_uri_to_path("file:///C:/Program Files/Steam/", pathlib.PureWindowsPath)
PureWindowsPath('C:/Program Files/Steam')
>>> file_uri_to_path("file:/proc/cpuinfo", pathlib.PurePosixPath)
PurePosixPath('/proc/cpuinfo')
>>> file_uri_to_path("file:c:/system32/etc/hosts", pathlib.PureWindowsPath)
PureWindowsPath('c:/system32/etc/hosts')
Эта функция работает для URI окон и файлов posix и будет обрабатывать URI файлов без раздела полномочий. Однако он НЕ будет выполнять проверку полномочий URI, поэтому это не будет выполнено:
IETF RFC 8089: "файловая" схема URI/2. Синтаксис
"Хост" - это полное доменное имя системы, на которой файл доступен. Это позволяет клиенту в другой системе знать, что он не может получить доступ к файловой системе, или, возможно, что ему нужно использовать другой локальный механизм для доступа к файлу.
Проверка (pytest) для функции:
import os
import pytest
def validate(file_uri, expected_windows_path, expected_posix_path):
if expected_windows_path is not None:
expected_windows_path_object = pathlib.PureWindowsPath(expected_windows_path)
if expected_posix_path is not None:
expected_posix_path_object = pathlib.PurePosixPath(expected_posix_path)
if expected_windows_path is not None:
if os.name == "nt":
assert file_uri_to_path(file_uri) == expected_windows_path_object
assert file_uri_to_path(file_uri, pathlib.PureWindowsPath) == expected_windows_path_object
if expected_posix_path is not None:
if os.name != "nt":
assert file_uri_to_path(file_uri) == expected_posix_path_object
assert file_uri_to_path(file_uri, pathlib.PurePosixPath) == expected_posix_path_object
def test_some_paths():
validate(pathlib.PureWindowsPath(r"C:\Windows\System32\Drivers\etc\hosts").as_uri(),
expected_windows_path=r"C:\Windows\System32\Drivers\etc\hosts",
expected_posix_path=r"/C:/Windows/System32/Drivers/etc/hosts")
validate(pathlib.PurePosixPath(r"/C:/Windows/System32/Drivers/etc/hosts").as_uri(),
expected_windows_path=r"C:\Windows\System32\Drivers\etc\hosts",
expected_posix_path=r"/C:/Windows/System32/Drivers/etc/hosts")
validate(pathlib.PureWindowsPath(r"C:\some dir\some file").as_uri(),
expected_windows_path=r"C:\some dir\some file",
expected_posix_path=r"/C:/some dir/some file")
validate(pathlib.PurePosixPath(r"/C:/some dir/some file").as_uri(),
expected_windows_path=r"C:\some dir\some file",
expected_posix_path=r"/C:/some dir/some file")
def test_invalid_url():
with pytest.raises(ValueError) as excinfo:
validate(r"file://C:/test/doc.txt",
expected_windows_path=r"test\doc.txt",
expected_posix_path=r"/test/doc.txt")
assert "is not absolute" in str(excinfo.value)
def test_escaped():
validate(r"file:///home/user/some%20file.txt",
expected_windows_path=None,
expected_posix_path=r"/home/user/some file.txt")
validate(r"file:///C:/some%20dir/some%20file.txt",
expected_windows_path="C:\some dir\some file.txt",
expected_posix_path=r"/C:/some dir/some file.txt")
def test_no_authority():
validate(r"file:c:/path/to/file",
expected_windows_path=r"c:\path\to\file",
expected_posix_path=None)
validate(r"file:/path/to/file",
expected_windows_path=None,
expected_posix_path=r"/path/to/file")
Этот вклад лицензируется (в дополнение к любым другим лицензиям, которые могут применяться) в соответствии с лицензией Zero-Clause BSD (0BSD) license
Разрешение на использование, копирование, изменение и/или распространение данного программного обеспечения для любых Настоящая цель предоставляется с платой или без нее.
ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ ПРЕДОСТАВЛЯЕТСЯ "КАК ЕСТЬ", И АВТОР ОТКАЗЫВАЕТСЯ ОТ ВСЕХ ГАРАНТИЙ. В ОТНОШЕНИИ НАСТОЯЩЕГО ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ, ВКЛЮЧАЯ ВСЕ ПОДРАЗУМЕВАЕМЫЕ ГАРАНТИИ ТОРГОВЛЯ И ФИТНЕС. НИ ПРИ КАКИХ ОБСТОЯТЕЛЬСТВАХ АВТОР НЕ НЕСЕТ ОТВЕТСТВЕННОСТИ ЗА ЛЮБЫЕ СПЕЦИАЛЬНЫЕ, НЕПОСРЕДСТВЕННЫЕ, НЕПОСРЕДСТВЕННЫЕ ИЛИ КОСВЕННЫЕ УБЫТКИ ИЛИ ЛЮБОЙ УЩЕРБ ЧТО ТАКОЕ РЕЗУЛЬТАТ ОТ УТРАТЫ ИСПОЛЬЗОВАНИЯ, ДАННЫХ ИЛИ ПРИБЫЛИ ДЕЙСТВИЕ КОНТРАКТА, ХАРАКТЕРИСТИКИ ИЛИ ДРУГОГО ПРАВОВОГО ДЕЙСТВИЯ, ВЫТЕКАЮЩЕГО ИЗ ИЛИ В СВЯЗИ С ИСПОЛЬЗОВАНИЕМ ИЛИ ВЫПОЛНЕНИЕМ НАСТОЯЩЕГО ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ.
Насколько это возможно в соответствии с законодательством, Iwan Aucamp отказался от всех авторских и смежных или смежных прав на этот вклад в обмен на стек. Эта работа издана из: Норвегия.
Решение от @colton7909 в основном правильное и помогло мне получить этот ответ, но имеет некоторые ошибки импорта с Python 3. Это и я думаю, что это лучший способ справиться с частью 'file://'
URL, чем просто отрубая первые 7 символов. Поэтому я считаю, что это самый идиоматичный способ сделать это с помощью стандартной библиотеки:
import urllib.parse
url_data = urllib.parse.urlparse('file:///home/user/some%20file.txt')
path = urllib.parse.unquote(url_data.path)
Этот пример должен создать строку '/home/user/some file.txt'