Skip to content

Commit

Permalink
Remove support for Python 2
Browse files Browse the repository at this point in the history
  • Loading branch information
larsevj committed Apr 30, 2024
1 parent a59d9e3 commit daff014
Show file tree
Hide file tree
Showing 17 changed files with 149 additions and 251 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:

- name: Install dependencies
run: |
pip install -r dev-requirements.txt -r requirements.txt
pip install -r requirements.txt
- name: Test
run: |
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,5 @@ Clone this repo and cd into it, then:

```
pip install -r requirements.txt
python -m unittest discover -v -s tests
python -m pytest -v -s tests
```
11 changes: 3 additions & 8 deletions cwrap/basecclass.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,12 @@
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
# for more details.

from __future__ import absolute_import, division, print_function, unicode_literals

import ctypes

import six

from .metacwrap import MetaCWrap


@six.add_metaclass(MetaCWrap)
class BaseCClass:
class BaseCClass(metaclass=MetaCWrap):
namespaces = {}

def __init__(self, c_pointer, parent=None, is_reference=False):
Expand All @@ -41,7 +36,7 @@ def __init__(self, c_pointer, parent=None, is_reference=False):
self.__is_reference = is_reference

def __new__(cls, *more, **kwargs):
obj = super(BaseCClass, cls).__new__(cls)
obj = super().__new__(cls)
obj.__c_pointer = None
obj.__parent = None
obj.__is_reference = False
Expand Down Expand Up @@ -119,7 +114,7 @@ def __eq__(self, other):
if isinstance(other, BaseCClass):
return self.__c_pointer == other.__c_pointer
else:
return super(BaseCClass, self) == other
return super() == other

def __hash__(self):
# Similar to last resort comparison; this returns the hash of the
Expand Down
9 changes: 2 additions & 7 deletions cwrap/basecenum.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,12 @@
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
# for more details.

from __future__ import absolute_import, division, print_function, unicode_literals

import ctypes

import six

from .metacwrap import MetaCWrap


@six.add_metaclass(MetaCWrap)
class BaseCEnum:
class BaseCEnum(metaclass=MetaCWrap):
enum_namespace = {}

def __init__(self, *args, **kwargs):
Expand All @@ -40,7 +35,7 @@ def __new__(cls, *args, **kwargs):

return enum
else:
obj = super(BaseCEnum, cls).__new__(cls, *args)
obj = super().__new__(cls, *args)
obj.name = None
obj.value = None
return obj
Expand Down
9 changes: 2 additions & 7 deletions cwrap/basecvalue.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
# for more details.

from __future__ import absolute_import, division, print_function, unicode_literals

from ctypes import (
c_bool,
c_byte,
Expand All @@ -32,13 +30,10 @@
pointer,
)

import six

from .metacwrap import MetaCWrap


@six.add_metaclass(MetaCWrap)
class BaseCValue:
class BaseCValue(metaclass=MetaCWrap):
DATA_TYPE = None
LEGAL_TYPES = [
c_byte,
Expand All @@ -56,7 +51,7 @@ class BaseCValue:
]

def __init__(self, value):
super(BaseCValue, self).__init__()
super().__init__()

if not self.DATA_TYPE in self.LEGAL_TYPES:
raise ValueError(
Expand Down
243 changes: 87 additions & 156 deletions cwrap/cfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,163 +16,94 @@

import os

import six

from .basecclass import BaseCClass
from .clib import load as cwrapload
from .prototype import Prototype

if six.PY2:
import ctypes

def copen(filename, mode="r"):
"""
This is a compatibility layer for functions taking FILE* pointers, and
should not be used unless absolutely needed.
In Python 2 this function is simply an alias for open. In Python 3,
however, it returns an instance of CWrapFile, a very light weight
wrapper around a FILE* instance.
"""
return open(filename, mode) # noqa

class CFILE(BaseCClass):
"""
Utility class to map a Python file handle <-> FILE* in C
"""

TYPE_NAME = "FILE"

_as_file = Prototype(ctypes.pythonapi, "void* PyFile_AsFile(py_object)")

def __init__(self, py_file):
"""
Takes a python file handle and looks up the underlying FILE *
The purpose of the CFILE class is to be able to use python
file handles when calling C functions which expect a FILE
pointer. A CFILE instance should be created based on the
Python file handle, and that should be passed to the function
expecting a FILE pointer.
The implementation is based on the ctypes object
pythonapi which is ctypes wrapping of the CPython api.
C-function:
void fprintf_hello(FILE * stream , const char * msg);
Python wrapper:
lib = clib.load( "lib.so" )
fprintf_hello = Prototype(lib, "void fprintf_hello( FILE , char* )")
Python use:
py_fileH = open("file.txt" , "w")
fprintf_hello( CFILE( py_fileH ) , "Message ...")
py_fileH.close()
If the supplied argument is not of type py_file the function
will raise a TypeException.
Examples: ecl.ecl.ecl_kw.EclKW.fprintf_grdecl()
"""
c_ptr = self._as_file(py_file)
try:
super(CFILE, self).__init__(c_ptr)
except ValueError as err:
raise TypeError(
"Sorry - the supplied argument is not a valid "
" Python file handle!"
) from err

self.py_file = py_file

def __del__(self):
pass


if six.PY3:
from .clib import load as cwrapload

class LibcPrototype(Prototype):
# Load the c standard library (on Linux passsing None does the trick)
lib = cwrapload("msvcrt" if os.name == "nt" else None)

def __init__(self, prototype, bind=False, allow_attribute_error=False):
super(LibcPrototype, self).__init__(
LibcPrototype.lib,
prototype,
bind=bind,
allow_attribute_error=allow_attribute_error,
)

def copen(filename, mode="r"):
"""
This is a compatibility layer for functions taking FILE* pointers, and
should not be used unless absolutely needed.
In Python 2 this function is simply an alias for open. In Python 3,
however, it returns an instance of CWrapFile, a very lightweight
wrapper around a FILE* instance.
"""
return CWrapFile(filename, mode)

class CWrapFile(BaseCClass):
"""
This is a compatibility layer for functions taking FILE* pointers, and
should not be used unless absolutely needed.
CWrapFile is a very lightweight wrapper around FILE* instances. It is
meant be used inplace of python file objects that are to be passed to
foreign function calls under python 3.
Example:
with cwrap.open('filename', 'mode') as f:
foreign_function_call(f)
"""

TYPE_NAME = "FILE"

_fopen = LibcPrototype("void* fopen (char*, char*)")
_fclose = LibcPrototype("int fclose (FILE)", bind=True)
_fflush = LibcPrototype("int fflush (FILE)", bind=True)

def __init__(self, fname, mode):
c_ptr = self._fopen(fname, mode)
self._mode = mode
self._fname = fname
self._closed = False

try:
super(CWrapFile, self).__init__(c_ptr)
except ValueError as err:
self._closed = True
raise IOError(f'Could not open file "{fname}" in mode {mode}') from err

def close(self):
if not self._closed:
self._fflush()
cs = self._fclose()
if cs != 0:
raise IOError("Failed to close file")
self._closed = True

def __enter__(self):
return self

def __exit__(self, exc_type, exc_val, exc_tb):
self.close()
return exc_type is None

def free(self):
self.close()

def __del__(self):
self.close()

def CFILE(f):
if not isinstance(f, CWrapFile):
raise TypeError(
"This function requires the use of CWrapFile, "
"not {} when running Python 3. See "
"help(cwrap.open) for more info".format(type(f).__name__)
)
return f
class LibcPrototype(Prototype):
# Load the c standard library (on Linux passsing None does the trick)
lib = cwrapload("msvcrt" if os.name == "nt" else None)

def __init__(self, prototype, bind=False, allow_attribute_error=False):
super().__init__(
LibcPrototype.lib,
prototype,
bind=bind,
allow_attribute_error=allow_attribute_error,
)


def copen(filename, mode="r"):
"""
This is a compatibility layer for functions taking FILE* pointers, and
should not be used unless absolutely needed.
It returns an instance of CWrapFile, a very lightweight
wrapper around a FILE* instance.
"""
return CWrapFile(filename, mode)


class CWrapFile(BaseCClass):
"""
This is a compatibility layer for functions taking FILE* pointers, and
should not be used unless absolutely needed.
CWrapFile is a very lightweight wrapper around FILE* instances. It is
meant be used inplace of python file objects that are to be passed to
foreign function calls under python 3.
Example:
with cwrap.open('filename', 'mode') as f:
foreign_function_call(f)
"""

TYPE_NAME = "FILE"

_fopen = LibcPrototype("void* fopen (char*, char*)")
_fclose = LibcPrototype("int fclose (FILE)", bind=True)
_fflush = LibcPrototype("int fflush (FILE)", bind=True)

def __init__(self, fname, mode):
c_ptr = self._fopen(fname, mode)
self._mode = mode
self._fname = fname
self._closed = False

try:
super().__init__(c_ptr)
except ValueError as err:
self._closed = True
raise OSError(f'Could not open file "{fname}" in mode {mode}') from err

def close(self):
if not self._closed:
self._fflush()
cs = self._fclose()
if cs != 0:
raise OSError("Failed to close file")
self._closed = True

def __enter__(self):
return self

def __exit__(self, exc_type, exc_val, exc_tb):
self.close()
return exc_type is None

def free(self):
self.close()

def __del__(self):
self.close()


def CFILE(f):
if not isinstance(f, CWrapFile):
raise TypeError(
"This function requires the use of CWrapFile, "
f"not {type(f).__name__} when running Python 3. See "
"help(cwrap.open) for more info"
)
return f
2 changes: 1 addition & 1 deletion cwrap/metacwrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def snakeCase(name):

class MetaCWrap(type):
def __init__(cls, name, bases, attrs):
super(MetaCWrap, cls).__init__(name, bases, attrs)
super().__init__(name, bases, attrs)

is_return_type = False
storage_type = None
Expand Down
Loading

0 comments on commit daff014

Please sign in to comment.