Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

process windows paths for pathlib fixes #111 #112

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 30 additions & 3 deletions oschmod/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@
import re
import stat
import string
import sys

PATHLIB_ERROR = "Pathlib not supported for <py34. Version found: {}"
IS_WINDOWS = platform.system() == 'Windows'
HAS_PYWIN32 = False
try:
Expand Down Expand Up @@ -335,7 +337,6 @@ def convert_stat_to_win(mode, user_type, object_type):

return win_perm


def win_get_user_type(sid, sids):
"""Given object and SIDs, return user type."""
if sid == sids[OWNER]:
Expand All @@ -360,8 +361,13 @@ def win_get_permissions(path):
"""Get the file or dir permissions."""
if not os.path.exists(path):
raise FileNotFoundError('Path %s could not be found.' % path)

if isinstance(path, str):
str_path = path
else:
str_path = _win_transform_pathlib_to_str(path)

return _win_get_permissions(path, get_object_type(path))
return _win_get_permissions(str_path, get_object_type(path))


def _get_basic_symbol_to_mode(symbol):
Expand Down Expand Up @@ -400,7 +406,12 @@ def win_set_permissions(path, mode):
if not os.path.exists(path):
raise FileNotFoundError('Path %s could not be found.' % path)

_win_set_permissions(path, mode, get_object_type(path))
if isinstance(path, str):
str_path = path
else:
str_path = _win_transform_pathlib_to_str(path)

_win_set_permissions(str_path, mode, get_object_type(path))


def _win_set_permissions(path, mode, object_type):
Expand Down Expand Up @@ -447,6 +458,22 @@ def _win_set_permissions(path, mode, object_type):
path, win32security.DACL_SECURITY_INFORMATION, sec_des)


def _win_transform_pathlib_to_str(path):
"""Transform pathlib.WindowsPath to a string to support win32security
operations when getting and setting permissions.
"""
# pathlib not available for <py34, primarily covering for py27
# sys.version_info implemented differently in py26 so use string.find()
py_version = sys.version
if py_version.startswith("2.6"):
raise RuntimeError(PATHLIB_ERROR.format(py_version))
elif sys.version_info.major < 3:
raise RuntimeError(PATHLIB_ERROR.format(py_version))
elif sys.version_info.minor < 4:
raise RuntimeError(PATHLIB_ERROR.format(py_version))
return "{}".format(path)


def print_win_inheritance(flags):
"""Display inheritance flags."""
print(" -Flags:", hex(flags))
Expand Down
1 change: 1 addition & 0 deletions requirements/test.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
mock==4.0.3
pytest==6.1.2
pywin32==301;platform_system=="Windows"
92 changes: 92 additions & 0 deletions tests/test_oschmod_pathlib.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
"""Unit tests for operations that might fail due to using Pathlib"""

import mock
import pytest

import oschmod

@mock.patch('oschmod._win_get_permissions')
@mock.patch('oschmod._win_transform_pathlib_to_str')
def test_win_get_permissions_string_path(transform_mock, get_permissions_mock):
oschmod.win_get_permissions('.')

transform_mock.assert_not_called()


@mock.patch('oschmod._win_set_permissions')
@mock.patch('oschmod._win_transform_pathlib_to_str')
def test_win_set_permissions_string_path(transform_mock, set_permissions_mock):
oschmod.win_set_permissions('.', 'mock_mode')

transform_mock.assert_not_called()

@mock.patch('oschmod._win_get_permissions')
@mock.patch('oschmod._win_transform_pathlib_to_str')
def test_win_get_permissions_path(transform_mock, get_permissions_mock):
mock_path = mock.MagicMock()

oschmod.win_get_permissions(mock_path)

transform_mock.assert_called_once_with(mock_path)


@mock.patch('oschmod._win_set_permissions')
@mock.patch('oschmod._win_transform_pathlib_to_str')
def test_win_set_permissions_path(transform_mock, set_permissions_mock):
mock_path = mock.MagicMock()

oschmod.win_set_permissions(mock_path, 'mock_mode')

transform_mock.assert_called_once_with(mock_path)


@mock.patch('oschmod.sys')
def test_win_transform_pathlib_to_str_negative_py26(mock_sys):
"""Tests versions that do not support pathlib throws an exception.
py26 sys.version_info implemented different from >py26"""

mock_sys.version = '2.6.0'

with pytest.raises(RuntimeError, match='Pathlib not supported for <py34.'):
oschmod._win_transform_pathlib_to_str('mock_path')

mock_sys.version_info.assert_not_called()


@pytest.mark.parametrize(
'major_version, minor_version',
[(2, 7), (2, 9), (3, 2), (3, 3)],
)
@mock.patch('oschmod.sys')
def test_win_transform_pathlib_to_str_negative(
mock_sys, major_version, minor_version
):
"""Tests versions that do not support pathlib throws an exception.
py27 is the only supported version by lib, but testing other edge
cases as well
"""
mock_sys.version = '{}.{}'.format(major_version, minor_version)
mock_sys.version_info.major = major_version
mock_sys.version_info.minor = minor_version

with pytest.raises(RuntimeError, match='Pathlib not supported for <py34.'):
oschmod._win_transform_pathlib_to_str('mock_path')


@pytest.mark.parametrize(
'major_version, minor_version',
[(3, 5), (3, 6), (3, 7), (3, 8)],
)
@mock.patch('oschmod.sys')
def test_win_transform_pathlib_to_str_positive(
mock_sys, major_version, minor_version
):
"""Tests pathlib is transformed into a string for windows for
supported versions."""
mock_sys.version = '{}.{}'.format(major_version, minor_version)
mock_sys.version_info.major = major_version
mock_sys.version_info.minor = minor_version

actual_path = oschmod._win_transform_pathlib_to_str('mock_path')

assert actual_path == 'mock_path'