Skip to content

Commit

Permalink
Fixes error message for read-only attributes #408
Browse files Browse the repository at this point in the history
  • Loading branch information
jasonb5 committed Aug 21, 2020
1 parent 28225f6 commit d8cf288
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 12 deletions.
1 change: 1 addition & 0 deletions Lib/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

# Errors
from .error import CDMSError # noqa
from .Cdunif import ReadOnlyKeyError
from lazy_object_proxy import Proxy
from . import dataset
from . import selectors
Expand Down
8 changes: 7 additions & 1 deletion Lib/dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -2105,7 +2105,13 @@ def createVariableCopy(self, var, id=None, attributes=None, axes=None, extbounds
if attname not in ["id", "datatype", "parent"]:
if isinstance(attval, string_types):
attval = str(attval)
setattr(newvar, str(attname), attval)
try:
setattr(newvar, str(attname), attval)
except Cdunif.ReadOnlyKeyError as e:
# Suppress the exception context
err = "Cannot write read-only attribute '{!s}', must be " \
"removed from '{!s}' variable before writing to file".format(e, var.id)
raise CDMSError(err) from None
if (attname == "_FillValue") or (attname == "missing_value"):
setattr(newvar, "_FillValue", attval)
setattr(newvar, "missing_value", attval)
Expand Down
7 changes: 1 addition & 6 deletions Lib/fvariable.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,12 +157,7 @@ def __setattr__(self, name, value):
if hasattr(self, "parent") and self.parent is None:
raise CDMSError(FileClosedWrite + self.id)
if (name not in self.__cdms_internals__) and (value is not None):
try:
setattr(self._obj_, str(name), value)
except Exception:
raise CDMSError(
"Setting %s.%s=%s" %
(self.id, name, repr(value)))
setattr(self._obj_, str(name), value)
self.attributes[name] = value
self.__dict__[name] = value

Expand Down
14 changes: 9 additions & 5 deletions Src/Cdunifmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ PyThread_type_lock Cdunif_lock;
#endif

static PyObject *CdunifError;
static PyObject *ReadOnlyKeyError;

/* Set error string */
static void Cdunif_seterror(void) {
Expand Down Expand Up @@ -2067,10 +2068,10 @@ static int PyCdunifFile_SetAttribute(PyCdunifFileObject *self, PyObject *nameobj
char *name = PyStr_AsString(nameobj);
if (check_if_open(self, 1)) {
if (strcmp(name, "dimensions") == 0
|| strcmp(name, "variables") == 0
|| strcmp(name, "variables") == 0
|| strcmp(name, "dimensioninfo") == 0
|| strcmp(name, "__dict__") == 0) {
PyErr_SetString(PyExc_TypeError, "object has read-only attributes");
PyErr_Format(ReadOnlyKeyError, "%s", name);
return -1;
}
define_mode(self, 1);
Expand Down Expand Up @@ -2423,9 +2424,10 @@ static int PyCdunifVariable_SetAttribute(PyCdunifVariableObject *self,
PyObject *nameobj, PyObject *value) {
char *name = PyStr_AsString(nameobj);
if (check_if_open(self->file, 1)) {
if (strcmp(name, "shape") == 0 || strcmp(name, "dimensions") == 0
if (strcmp(name, "shape") == 0
|| strcmp(name, "dimensions") == 0
|| strcmp(name, "__dict__") == 0) {
PyErr_SetString(PyExc_TypeError, "object has read-only attributes");
PyErr_Format(ReadOnlyKeyError, "%s", name);
return -1;
}
define_mode(self->file, 1);
Expand Down Expand Up @@ -3456,9 +3458,11 @@ MODULE_INIT_FUNC (Cdunif) {
PyCapsule_New((void *) PyCdunif_API, "_C_API", NULL));


CdunifError = PyStr_FromString("CdunifError");
CdunifError = PyStr_FromString("CdunifError");
ReadOnlyKeyError = PyErr_NewException("Cdunif.ReadOnlyKeyError", NULL, NULL);

PyDict_SetItemString(d, "CdunifError", CdunifError);
PyDict_SetItemString(d, "ReadOnlyKeyError", ReadOnlyKeyError);

/* Check for errors */
if (PyErr_Occurred())
Expand Down
31 changes: 31 additions & 0 deletions tests/test_dataset_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
import string
import os
import sys
import cdat_info
import subprocess
import shutil

cdms2.setNetcdfUseParallelFlag(0)

Expand All @@ -21,6 +24,34 @@ def setUp(self):
def testFileAttributes(self):
self.assertEqual(self.file.id, "test")

def testWriteReadOnlyAttribute(self):
out = self.getTempFile("read_only.nc", "w")
out.write(self.u)
out.close()

temp = self.getTempFile("read_only.nc", "a")

with self.assertRaises(cdms2.ReadOnlyKeyError):
setattr(temp, "dimensions", "test")

with self.assertRaises(cdms2.ReadOnlyKeyError):
setattr(temp["u"], "dimensions", "test")

def testWriteThroughReadOnlyAtttribute(self):
iname = os.path.join(cdat_info.get_sampledata_path(), "clt.nc")
oname = os.path.join(os.getcwd(), "clt-modded.nc")

shutil.copyfile(iname, oname)

subprocess.run(["ncatted", "-a", "dimensions,clt,c,c,'lat lon'", oname])

ifile = cdms2.open(oname)
data = ifile("clt")
ifile.close()

with cdms2.open(oname, "w") as ofile, self.assertRaises(cdms2.CDMSError):
ofile.write(data)

def testScalarSlice(self):
u = self.u
scalar = u[0,0,0]
Expand Down

0 comments on commit d8cf288

Please sign in to comment.