1
0
mirror of https://github.com/TREX-CoE/trexio.git synced 2024-12-22 20:35:44 +01:00

Merge pull request #75 from TREX-CoE/add-inquire-functionality

Add inquire functionality
This commit is contained in:
Anthony Scemama 2022-01-19 15:13:57 +01:00 committed by GitHub
commit 51c43fe1ac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 223 additions and 64 deletions

View File

@ -1,4 +1,4 @@
#!/bin/bash
#!/bin/bash
set -x
set -e
@ -38,12 +38,12 @@ python3 -m pip install -r requirements.txt
# Create build directory and compile extension files (*.c)
# --no-user-cfg disables custom .cfg files of the user machine, so that only setup.cfg is used
#python3 -s setup.py --no-user-cfg build
#python3 -s setup.py --no-user-cfg build
# Local inplace build of the .so module with SWIG-produced pytrexio_wrap.c (from the SWIG documentation)
#python3 setup.py build_ext --inplace --swig-opts="-modern"
# Create distributions:
# Create distributions:
# OLD WAY (DEPRECATED BY PYPA)
# 1) sdist produces .tar.gz with all files necessary for manual compilation;
@ -54,14 +54,7 @@ python3 -m pip install -r requirements.txt
python3 -m build --sdist --wheel --outdir dist/
# Install pytrexio in the current environment from the aforementioned wheel
# OLD WAY
# --force-reinstall is needed here because build-system pre-installs pytrexio in the environment
# but does not install things in the corresponding site-packages directory
#python3 -m pip install dist/trexio-*.whl --force-reinstall
# NEW WAY
python3 -m pip install dist/trexio-*.whl
python3 -m pip install dist/trexio-*.whl --force-reinstall
# Run the command below in the root directory to install the package in 'editable' (-e) mode without dependencies (--no-deps)
#python -m pip install -e . --no-deps
@ -83,7 +76,6 @@ rm -rf build dist trexio.egg-info
# Additional information related to the installation of the TREXIO Python API
#Removing MANIFEST.in leads to issues in the installation. In particular, the .c and .h source files do not get copied
#from the src/ directory into the tar.gz which is produced by setup sdist command.
#Removing MANIFEST.in leads to issues in the installation. In particular, the .c and .h source files do not get copied
#from the src/ directory into the tar.gz which is produced by setup sdist command.
#These source files are required to build the pytrexio.so extension module, which is needed for the Python API.

View File

@ -40,6 +40,7 @@ except:
# create TREXIO file and open it for writing
test_file = trexio.File(output_filename, mode='w', back_end=TEST_TREXIO_BACKEND)
assert test_file.exists
# Print docstring of the trexio.open function
#print(trexio.open.__doc__)
@ -153,6 +154,7 @@ del test_file
# open previously created TREXIO file, now in 'read' mode
test_file2 = trexio.File(output_filename, 'r', TEST_TREXIO_BACKEND)
assert test_file2.exists
# check for existence of some of the previously written variables
assert trexio.has_nucleus_num

View File

@ -1,5 +1,4 @@
#+TITLE: Front end API
break;
#+PROPERTY: comments org
#+SETUPFILE: ../../docs/theme.setup
# -*- mode: org -*-
@ -696,12 +695,15 @@ class File:
self.back_end = back_end
self.isOpen = False
self.exists = False
if pytrexio_s is None:
self.pytrexio_s = open(filename, mode, back_end)
self.pytrexio_s = _open(filename, mode, back_end)
self.isOpen = True
self.exists = True
else:
self.pytrexio_s = pytrexio_s
self.isOpen = None
self.exists = None
self.info = info
@ -710,17 +712,23 @@ class File:
"""Close a TREXIO File."""
if self.isOpen:
close(self.pytrexio_s)
_close(self.pytrexio_s)
self.isOpen = False
else:
raise Exception("TREXIO File object has not been opened.")
def inquire(self):
"""Inquire whether a TREXIO file exists."""
self.exists = _inquire(self.filename)
def __del__(self):
"""This is a TREXIO File destructor."""
if self.isOpen:
close(self.pytrexio_s)
_close(self.pytrexio_s)
elif self.isOpen is None:
raise Exception("[WIP]: TREXIO file handle provided but what if the file is already closed?")
else:
@ -972,7 +980,7 @@ end interface
*** Python
#+begin_src python :tangle basic_python.py
def open(file_name: str, mode: str, back_end: int):
def _open(file_name: str, mode: str, back_end: int):
"""Create TREXIO file or open existing one.
Parameters:
@ -1149,7 +1157,7 @@ end interface
*** Python
#+begin_src python :tangle basic_python.py
def close(trexio_file):
def _close(trexio_file):
"""Close TREXIO file.
Parameter is a ~trexio_file~ object that has been created by a call to ~open~ function.
@ -1163,6 +1171,77 @@ def close(trexio_file):
raise
#+end_src
** File existence
~trexio_inquire~ check whether TREXIO file exists.
input parameters:
~file_name~ - string containing file name
output:
~trexio_exit_code~ exit code.
*** C
#+begin_src c :tangle prefix_front.h :exports none
trexio_exit_code trexio_inquire(const char* file_name);
#+end_src
#+begin_src c :tangle prefix_front.c
trexio_exit_code
trexio_inquire (const char* file_name)
{
if (file_name == NULL || file_name[0] == '\0') return TREXIO_INVALID_ARG_1;
/* First check if the TREXIO file exists and if it is a directory */
trexio_exit_code rc_text = trexio_text_inquire(file_name);
#ifdef HAVE_HDF5
/* FILE_ERROR here means that the file exists but it is not a directory -> check with HDF5 */
if (rc_text == TREXIO_FILE_ERROR) {
trexio_exit_code rc_hdf5 = trexio_hdf5_inquire(file_name);
return rc_hdf5;
/* If rc_text is TREXIO_SUCCESS -> file is a TREXIO directory; TREXIO_FAILURE -> file/directory does not exist */
} else {
return rc_text;
}
#else
return rc_text;
#endif
}
#+end_src
*** Fortran
The function below is a C binding.
The front end Fortran function for ~trexio_inquire~ can be found in the ~Fortran helper/wrapper functions~.
#+begin_src f90 :tangle prefix_fortran.f90
interface
integer function trexio_inquire_c (filename) bind(C, name="trexio_inquire")
use, intrinsic :: iso_c_binding
import
character(kind=c_char), dimension(*) :: filename
end function trexio_inquire_c
end interface
#+end_src
*** Python
#+begin_src python :tangle basic_python.py
def _inquire(file_name: str) -> bool:
"""Check whether ~file_name~ TREXIO file exists.
"""
rc = pytr.trexio_inquire(trexio_file_name)
if rc == TREXIO_SUCCESS:
return True
elif rc == TREXIO_FAILURE:
return False
else:
raise Error(rc)
#+end_src
* Templates for front end
** Description
@ -1769,7 +1848,7 @@ trexio_write_$group_dset$_64 (trexio_t* const file, const $group_dset_dtype_doub
case TREXIO_HDF5:
#ifdef HAVE_HDF5
rc = trexio_hdf5_write_$group_dset$(file,
rc = trexio_hdf5_write_$group_dset$(file,
(const $group_dset_dtype_double$*) $group_dset$_p,
rank, dims);
break;
@ -2629,7 +2708,7 @@ trexio_write_$group_dset$(trexio_t* const file,
if (file->one_based) {
uint64_t index_size = rank * buffer_size;
int32_t* index_sparse_p = CALLOC(index_size, int32_t);
if (index_sparse_p == NULL) return TREXIO_ALLOCATION_FAILED;
@ -3801,6 +3880,23 @@ contains
end function trexio_open
#+end_src
The function below adapts the original C-based ~trexio_inquire~ for Fortran.
This is needed due to the same reasons as for ~trexio_open~ function.
Note, that Fortran interface calls the main ~TREXIO~ API, which is written in C.
#+begin_src f90 :tangle helper_fortran.f90
integer function trexio_inquire (filename)
use, intrinsic :: iso_c_binding
implicit none
character(len=*), intent(in) :: filename
character(len=len_trim(filename)+1) :: filename_c
filename_c = trim(filename) // c_null_char
trexio_inquire = trexio_inquire_c(filename_c)
end function trexio_inquire
#+end_src
The subroutine below transforms an array of Fortran strings into one big string using ~TREXIO_DELIM~ symbol
as a delimeter and adds ~NULL~ character in the end in order to properly pass the desired string to
C API. This is needed due to the fact that strings in C are terminated by ~NULL~ character ~\0~.

View File

@ -69,13 +69,29 @@ typedef struct trexio_hdf5_s {
} trexio_hdf5_t;
#+end_src
** Template for HDF5 init/deinit
#+begin_src c :tangle struct_hdf5.h :exports none
trexio_exit_code trexio_hdf5_init(trexio_t* const file);
trexio_exit_code trexio_hdf5_deinit(trexio_t* const file);
trexio_exit_code trexio_hdf5_inquire(const char* file_name);
#+end_src
** Template for HDF5 init/deinit
#+begin_src c :tangle basic_hdf5.c
trexio_exit_code
trexio_hdf5_inquire(const char* file_name)
{
/* H5Fis_hdf5 determines whether file is in HDF5 format */
htri_t rc = H5Fis_hdf5(file_name);
if (rc > 0 ) {
return TREXIO_SUCCESS; //exists and HDF5
} else if (rc == 0) {
return TREXIO_FILE_ERROR; //exists but not HDF5
} else {
return TREXIO_FAILURE; //does not exist or function fails
}
}
#+end_src
#+begin_src c :tangle basic_hdf5.c
trexio_exit_code
@ -134,7 +150,9 @@ trexio_hdf5_init (trexio_t* const file)
return TREXIO_SUCCESS;
}
#+end_src
#+begin_src c :tangle basic_hdf5.c
trexio_exit_code
trexio_hdf5_deinit (trexio_t* const file)
{

View File

@ -105,6 +105,33 @@ typedef struct trexio_text_s {
#+begin_src c :tangle basic_text.h :exports none
trexio_exit_code trexio_text_init(trexio_t* const file);
trexio_exit_code trexio_text_inquire(const char* file_name);
trexio_exit_code trexio_text_deinit(trexio_t* const file);
trexio_exit_code trexio_text_lock(trexio_t* const file);
trexio_exit_code trexio_text_unlock(trexio_t* const file);
#+end_src
#+begin_src c :tangle basic_text.c
trexio_exit_code
trexio_text_inquire (const char* file_name)
{
/* Check if the file with "file_name" exists and that it is a directory */
struct stat st;
int rc = stat(file_name, &st);
bool file_exists = rc == 0;
if (file_exists) {
bool is_a_directory = st.st_mode & S_IFDIR;
if (!is_a_directory) return TREXIO_FILE_ERROR;
return TREXIO_SUCCESS;
} else {
return TREXIO_FAILURE;
}
}
#+end_src
#+begin_src c :tangle basic_text.c
@ -119,30 +146,19 @@ trexio_text_init (trexio_t* const file)
/* Put all pointers to NULL but leave parent untouched */
memset(&(f->parent)+1,0,sizeof(trexio_text_t)-sizeof(trexio_t));
/* If directory doesn't exist, create it in write mode */
struct stat st;
/* Check if directory exists */
trexio_exit_code rc;
rc = trexio_text_inquire(file->file_name);
/* TREXIO file exists but is not a directory */
if (rc == TREXIO_FILE_ERROR) return rc;
/* If directory does not exist - create it in write mode */
if (rc == TREXIO_FAILURE) {
int rc = stat(file->file_name, &st);
if (file->mode == 'r') return TREXIO_READONLY;
bool file_exists = rc == 0;
int rc_dir = mkdir(file->file_name, 0777);
if (rc_dir != 0) return TREXIO_ERRNO;
if (file_exists) {
bool is_a_directory = st.st_mode & S_IFDIR;
if (!is_a_directory) {
return TREXIO_FILE_ERROR;
}
} else {
if (file->mode == 'r') {
return TREXIO_READONLY;
}
rc = mkdir(file->file_name, 0777);
if (rc != 0) {
return TREXIO_ERRNO;
}
}
/* Create the lock file in the directory */
@ -166,7 +182,7 @@ trexio_text_init (trexio_t* const file)
if (errno == EACCES) {
/* The directory is read-only and the lock file can't be written.
Create a dummy temporary file for dummy locking.
*/
,*/
char dirname[TREXIO_MAX_FILENAME_LENGTH] = "/tmp/trexio.XXXXXX";
if (mkdtemp(dirname) == NULL) return TREXIO_ERRNO;
strncpy (file_name, dirname, TREXIO_MAX_FILENAME_LENGTH);
@ -184,10 +200,6 @@ trexio_text_init (trexio_t* const file)
}
#+end_src
#+begin_src c :tangle basic_text.h :exports none
trexio_exit_code trexio_text_lock(trexio_t* const file);
#+end_src
#+begin_src c :tangle basic_text.c
trexio_exit_code trexio_text_lock(trexio_t* const file) {
if (file == NULL) return TREXIO_INVALID_ARG_1;
@ -210,15 +222,6 @@ trexio_exit_code trexio_text_lock(trexio_t* const file) {
}
#+end_src
#+begin_src c :tangle basic_text.h :exports none
trexio_exit_code trexio_text_deinit(trexio_t* const file);
#+end_src
#+begin_src c :tangle basic_text.h :exports none
trexio_exit_code trexio_text_unlock(trexio_t* const file);
#+end_src
#+begin_src c :tangle basic_text.c
trexio_exit_code
trexio_text_unlock (trexio_t* const file)

View File

@ -85,7 +85,7 @@ static int test_open_errors (const back_end_t backend) {
fprintf(stderr, "%s \n", trexio_string_of_error(rc));
// open existing file with non-supported back end, should return TREXIO_INVALID_ARG_3
file = trexio_open(TREXIO_VOID, 'w', 666, &rc);
file = trexio_open(TREXIO_FILE, 'w', 666, &rc);
assert (file == NULL);
assert (rc == TREXIO_INVALID_ARG_3);
fprintf(stderr, "%s \n", trexio_string_of_error(rc));
@ -96,6 +96,28 @@ static int test_open_errors (const back_end_t backend) {
}
static int test_inquire (const back_end_t backend) {
/* Try to call trexio_inquire function */
trexio_exit_code rc;
/*================= START OF TEST ==================*/
// inquire non-existing file
rc = trexio_inquire(TREXIO_VOID);
assert (rc == TREXIO_FAILURE);
// inquire existing file
rc = trexio_inquire(TREXIO_FILE);
assert (rc == TREXIO_SUCCESS);
/*================= END OF TEST ==================*/
return 0;
}
int main(void) {
/*============== Test launcher ================*/
@ -107,11 +129,10 @@ int main(void) {
test_open_w (TREXIO_FILE, TEST_BACKEND);
test_open_r (TREXIO_FILE, TEST_BACKEND);
test_open_errors(TEST_BACKEND);
test_inquire (TEST_BACKEND);
rc = system(RM_COMMAND);
assert (rc == 0);
return 0;
}

View File

@ -85,7 +85,7 @@ static int test_open_errors (const back_end_t backend) {
fprintf(stderr, "%s \n", trexio_string_of_error(rc));
// open existing file with non-supported back end, should return TREXIO_INVALID_ARG_3
file = trexio_open(TREXIO_VOID, 'w', 666, &rc);
file = trexio_open(TREXIO_FILE, 'w', 666, &rc);
assert (file == NULL);
assert (rc == TREXIO_INVALID_ARG_3);
fprintf(stderr, "%s \n", trexio_string_of_error(rc));
@ -96,6 +96,28 @@ static int test_open_errors (const back_end_t backend) {
}
static int test_inquire (const back_end_t backend) {
/* Try to call trexio_inquire function */
trexio_exit_code rc;
/*================= START OF TEST ==================*/
// inquire non-existing file
rc = trexio_inquire(TREXIO_VOID);
assert (rc == TREXIO_FAILURE);
// inquire existing file
rc = trexio_inquire(TREXIO_FILE);
assert (rc == TREXIO_SUCCESS);
/*================= END OF TEST ==================*/
return 0;
}
int main(void) {
/*============== Test launcher ================*/
@ -107,11 +129,10 @@ int main(void) {
test_open_w (TREXIO_FILE, TEST_BACKEND);
test_open_r (TREXIO_FILE, TEST_BACKEND);
test_open_errors(TEST_BACKEND);
test_inquire (TEST_BACKEND);
rc = system(RM_COMMAND);
assert (rc == 0);
return 0;
}

View File

@ -103,6 +103,9 @@ subroutine test_write(file_name, back_end)
! ================= START OF TEST ===================== !
rc = trexio_inquire(file_name)
call trexio_assert(rc, TREXIO_FAILURE)
trex_file = trexio_open(file_name, 'w', back_end, rc)
call trexio_assert(rc, TREXIO_SUCCESS)
@ -217,6 +220,9 @@ subroutine test_read(file_name, back_end)
! ================= START OF TEST ===================== !
rc = trexio_inquire(file_name)
call trexio_assert(rc, TREXIO_SUCCESS)
trex_file = trexio_open(file_name, 'r', back_end, rc)
call trexio_assert(rc, TREXIO_SUCCESS)