Skip to content

Commit

Permalink
process windows paths for pathlib fixes YakDriver#111
Browse files Browse the repository at this point in the history
  • Loading branch information
zapplecat committed Aug 22, 2021
1 parent 44faf9e commit d523a21
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 3 deletions.
25 changes: 22 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,9 @@ 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)
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 @@ -399,8 +401,9 @@ def win_set_permissions(path, mode):
"""Set the file or dir permissions."""
if not os.path.exists(path):
raise FileNotFoundError('Path %s could not be found.' % path)
str_path = _win_transform_pathlib_to_str(path)

_win_set_permissions(path, mode, get_object_type(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 +450,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"
73 changes: 73 additions & 0 deletions tests/test_oschmod_pathlib.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
"""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(transform_mock, get_permissions_mock):
oschmod.win_get_permissions('.')

transform_mock.assert_called_once_with('.')


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

transform_mock.assert_called_once_with('.')


@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'

0 comments on commit d523a21

Please sign in to comment.