Merge pull request #3615 from hugovk/imagecms-deprecations

Add warnings to deprecated CMS profile attributes
This commit is contained in:
Andrew Murray 2019-04-01 17:35:32 +11:00 committed by GitHub
commit f707affbde
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 152 additions and 73 deletions

View File

@ -309,7 +309,7 @@ class TestImageCms(PillowTestCase):
2: (False, False, True),
3: (False, False, True)
})
self.assertEqual(p.color_space, 'RGB')
self.assertIsNone(p.colorant_table)
self.assertIsNone(p.colorant_table_out)
self.assertIsNone(p.colorimetric_intent)
@ -361,16 +361,9 @@ class TestImageCms(PillowTestCase):
(5000.722328847392,))
self.assertEqual(p.model,
'IEC 61966-2-1 Default RGB Colour Space - sRGB')
self.assertEqual(p.pcs, 'XYZ')
self.assertIsNone(p.perceptual_rendering_intent_gamut)
self.assertEqual(p.product_copyright,
'Copyright International Color Consortium, 2009')
self.assertEqual(p.product_desc, 'sRGB IEC61966-2-1 black scaled')
self.assertEqual(p.product_description,
'sRGB IEC61966-2-1 black scaled')
self.assertEqual(p.product_manufacturer, '')
self.assertEqual(
p.product_model, 'IEC 61966-2-1 Default RGB Colour Space - sRGB')
self.assertEqual(
p.profile_description, 'sRGB IEC61966-2-1 black scaled')
self.assertEqual(
@ -393,6 +386,40 @@ class TestImageCms(PillowTestCase):
'Reference Viewing Condition in IEC 61966-2-1')
self.assertEqual(p.xcolor_space, 'RGB ')
def test_deprecations(self):
self.skip_missing()
o = ImageCms.getOpenProfile(SRGB)
p = o.profile
def helper_deprecated(attr, expected):
result = self.assert_warning(DeprecationWarning, getattr, p, attr)
self.assertEqual(result, expected)
# p.color_space
helper_deprecated("color_space", "RGB")
# p.pcs
helper_deprecated("pcs", "XYZ")
# p.product_copyright
helper_deprecated(
"product_copyright", "Copyright International Color Consortium, 2009"
)
# p.product_desc
helper_deprecated("product_desc", "sRGB IEC61966-2-1 black scaled")
# p.product_description
helper_deprecated("product_description", "sRGB IEC61966-2-1 black scaled")
# p.product_manufacturer
helper_deprecated("product_manufacturer", "")
# p.product_model
helper_deprecated(
"product_model", "IEC 61966-2-1 Default RGB Colour Space - sRGB"
)
def test_profile_typesafety(self):
""" Profile init type safety

View File

@ -79,6 +79,26 @@ PILLOW_VERSION constant
``PILLOW_VERSION`` has been deprecated and will be removed in the next
major release. Use ``__version__`` instead.
ImageCms.CmsProfile attributes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. deprecated:: 3.2.0
Some attributes in ``ImageCms.CmsProfile`` are deprecated. From 6.0.0, they issue a
``DeprecationWarning``:
======================== ===============================
Deprecated Use instead
======================== ===============================
``color_space`` Padded ``xcolor_space``
``pcs`` Padded ``connection_space``
``product_copyright`` Unicode ``copyright``
``product_desc`` Unicode ``profile_description``
``product_description`` Unicode ``profile_description``
``product_manufacturer`` Unicode ``manufacturer``
``product_model`` Unicode ``model``
======================== ===============================
Removed features
----------------

View File

@ -132,21 +132,21 @@ can be easily displayed in a chromaticity diagram, for example).
.. py:attribute:: manufacturer
The (english) display string for the device manufacturer (see
The (English) display string for the device manufacturer (see
9.2.22 of ICC.1:2010).
:type: :py:class:`unicode` or ``None``
.. py:attribute:: model
The (english) display string for the device model of the device
The (English) display string for the device model of the device
for which this profile is created (see 9.2.23 of ICC.1:2010).
:type: :py:class:`unicode` or ``None``
.. py:attribute:: profile_description
The (english) display string for the profile description (see
The (English) display string for the profile description (see
9.2.41 of ICC.1:2010).
:type: :py:class:`unicode` or ``None``
@ -269,14 +269,14 @@ can be easily displayed in a chromaticity diagram, for example).
.. py:attribute:: viewing_condition
The (english) display string for the viewing conditions (see
The (English) display string for the viewing conditions (see
9.2.48 of ICC.1:2010).
:type: :py:class:`unicode` or ``None``
.. py:attribute:: screening_description
The (english) display string for the screening conditions.
The (English) display string for the screening conditions.
This tag was available in ICC 3.2, but it is removed from
version 4.

View File

@ -99,6 +99,24 @@ version.
Use ``PIL.__version__`` instead.
ImageCms.CmsProfile attributes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Some attributes in ``ImageCms.CmsProfile`` have been deprecated since Pillow 3.2.0. From
6.0.0, they issue a ``DeprecationWarning``:
======================== ===============================
Deprecated Use instead
======================== ===============================
``color_space`` Padded ``xcolor_space``
``pcs`` Padded ``connection_space``
``product_copyright`` Unicode ``copyright``
``product_desc`` Unicode ``profile_description``
``product_description`` Unicode ``profile_description``
``product_manufacturer`` Unicode ``manufacturer``
``product_model`` Unicode ``model``
======================== ===============================
MIME type improvements
^^^^^^^^^^^^^^^^^^^^^^

View File

@ -686,11 +686,11 @@ def getProfileName(profile):
# // name was "%s - %s" (model, manufacturer) || Description ,
# // but if the Model and Manufacturer were the same or the model
# // was long, Just the model, in 1.x
model = profile.profile.product_model
manufacturer = profile.profile.product_manufacturer
model = profile.profile.model
manufacturer = profile.profile.manufacturer
if not (model or manufacturer):
return profile.profile.product_description + "\n"
return (profile.profile.profile_description or "") + "\n"
if not manufacturer or len(model) > 30:
return model + "\n"
return "%s - %s\n" % (model, manufacturer)
@ -727,8 +727,8 @@ def getProfileInfo(profile):
# Python, not C. the white point bits weren't working well,
# so skipping.
# info was description \r\n\r\n copyright \r\n\r\n K007 tag \r\n\r\n whitepoint
description = profile.profile.product_description
cpright = profile.profile.product_copyright
description = profile.profile.profile_description
cpright = profile.profile.copyright
arr = []
for elt in (description, cpright):
if elt:
@ -762,7 +762,7 @@ def getProfileCopyright(profile):
# add an extra newline to preserve pyCMS compatibility
if not isinstance(profile, ImageCmsProfile):
profile = ImageCmsProfile(profile)
return profile.profile.product_copyright + "\n"
return (profile.profile.copyright or "") + "\n"
except (AttributeError, IOError, TypeError, ValueError) as v:
raise PyCMSError(v)
@ -790,7 +790,7 @@ def getProfileManufacturer(profile):
# add an extra newline to preserve pyCMS compatibility
if not isinstance(profile, ImageCmsProfile):
profile = ImageCmsProfile(profile)
return profile.profile.product_manufacturer + "\n"
return (profile.profile.manufacturer or "") + "\n"
except (AttributeError, IOError, TypeError, ValueError) as v:
raise PyCMSError(v)
@ -819,7 +819,7 @@ def getProfileModel(profile):
# add an extra newline to preserve pyCMS compatibility
if not isinstance(profile, ImageCmsProfile):
profile = ImageCmsProfile(profile)
return profile.profile.product_model + "\n"
return (profile.profile.model or "") + "\n"
except (AttributeError, IOError, TypeError, ValueError) as v:
raise PyCMSError(v)
@ -848,7 +848,7 @@ def getProfileDescription(profile):
# add an extra newline to preserve pyCMS compatibility
if not isinstance(profile, ImageCmsProfile):
profile = ImageCmsProfile(profile)
return profile.profile.product_description + "\n"
return (profile.profile.profile_description or "") + "\n"
except (AttributeError, IOError, TypeError, ValueError) as v:
raise PyCMSError(v)

View File

@ -736,12 +736,12 @@ _xyz3_py(cmsCIEXYZ* XYZ)
cmsXYZ2xyY(&xyY[2], &XYZ[2]);
return Py_BuildValue("(((d,d,d),(d,d,d),(d,d,d)),((d,d,d),(d,d,d),(d,d,d)))",
XYZ[0].X, XYZ[0].Y, XYZ[0].Z,
XYZ[1].X, XYZ[1].Y, XYZ[1].Z,
XYZ[2].X, XYZ[2].Y, XYZ[2].Z,
xyY[0].x, xyY[0].y, xyY[0].Y,
xyY[1].x, xyY[1].y, xyY[1].Y,
xyY[2].x, xyY[2].y, xyY[2].Y);
XYZ[0].X, XYZ[0].Y, XYZ[0].Z,
XYZ[1].X, XYZ[1].Y, XYZ[1].Z,
XYZ[2].X, XYZ[2].Y, XYZ[2].Z,
xyY[0].x, xyY[0].y, xyY[0].Y,
xyY[1].x, xyY[1].y, xyY[1].Y,
xyY[2].x, xyY[2].y, xyY[2].Y);
}
static PyObject*
@ -784,9 +784,9 @@ _profile_read_ciexyy_triple(CmsProfileObject* self, cmsTagSignature info)
/* Note: lcms does all the heavy lifting and error checking (nr of
channels == 3). */
return Py_BuildValue("((d,d,d),(d,d,d),(d,d,d)),",
triple->Red.x, triple->Red.y, triple->Red.Y,
triple->Green.x, triple->Green.y, triple->Green.Y,
triple->Blue.x, triple->Blue.y, triple->Blue.Y);
triple->Red.x, triple->Red.y, triple->Red.Y,
triple->Green.x, triple->Green.y, triple->Green.Y,
triple->Blue.x, triple->Blue.y, triple->Blue.Y);
}
static PyObject*
@ -818,12 +818,12 @@ _profile_read_named_color_list(CmsProfileObject* self, cmsTagSignature info)
for (i = 0; i < n; i++) {
PyObject* str;
cmsNamedColorInfo(ncl, i, name, NULL, NULL, NULL, NULL);
str = PyUnicode_FromString(name);
if (str == NULL) {
Py_DECREF(result);
Py_INCREF(Py_None);
return Py_None;
}
str = PyUnicode_FromString(name);
if (str == NULL) {
Py_DECREF(result);
Py_INCREF(Py_None);
return Py_None;
}
PyList_SET_ITEM(result, i, str);
}
@ -845,9 +845,9 @@ static cmsBool _calculate_rgb_primaries(CmsProfileObject* self, cmsCIEXYZTRIPLE*
// transform from our profile to XYZ using doubles for highest precision
hTransform = cmsCreateTransform(self->profile, TYPE_RGB_DBL,
hXYZ, TYPE_XYZ_DBL,
INTENT_RELATIVE_COLORIMETRIC,
cmsFLAGS_NOCACHE | cmsFLAGS_NOOPTIMIZE);
hXYZ, TYPE_XYZ_DBL,
INTENT_RELATIVE_COLORIMETRIC,
cmsFLAGS_NOCACHE | cmsFLAGS_NOOPTIMIZE);
cmsCloseProfile(hXYZ);
if (hTransform == NULL)
return 0;
@ -886,31 +886,31 @@ _is_intent_supported(CmsProfileObject* self, int clut)
n = cmsGetSupportedIntents(INTENTS,
intent_ids,
intent_descs);
intent_ids,
intent_descs);
for (i = 0; i < n; i++) {
int intent = (int) intent_ids[i];
PyObject* id;
PyObject* entry;
PyObject* entry;
/* Only valid for ICC Intents (otherwise we read invalid memory in lcms cmsio1.c). */
if (!(intent == INTENT_PERCEPTUAL || intent == INTENT_RELATIVE_COLORIMETRIC
|| intent == INTENT_SATURATION || intent == INTENT_ABSOLUTE_COLORIMETRIC))
continue;
/* Only valid for ICC Intents (otherwise we read invalid memory in lcms cmsio1.c). */
if (!(intent == INTENT_PERCEPTUAL || intent == INTENT_RELATIVE_COLORIMETRIC
|| intent == INTENT_SATURATION || intent == INTENT_ABSOLUTE_COLORIMETRIC))
continue;
id = PyInt_FromLong((long) intent);
entry = Py_BuildValue("(OOO)",
_check_intent(clut, self->profile, intent, LCMS_USED_AS_INPUT) ? Py_True : Py_False,
_check_intent(clut, self->profile, intent, LCMS_USED_AS_OUTPUT) ? Py_True : Py_False,
_check_intent(clut, self->profile, intent, LCMS_USED_AS_PROOF) ? Py_True : Py_False);
if (id == NULL || entry == NULL) {
Py_XDECREF(id);
Py_XDECREF(entry);
Py_XDECREF(result);
Py_INCREF(Py_None);
return Py_None;
}
PyDict_SetItem(result, id, entry);
id = PyInt_FromLong((long) intent);
entry = Py_BuildValue("(OOO)",
_check_intent(clut, self->profile, intent, LCMS_USED_AS_INPUT) ? Py_True : Py_False,
_check_intent(clut, self->profile, intent, LCMS_USED_AS_OUTPUT) ? Py_True : Py_False,
_check_intent(clut, self->profile, intent, LCMS_USED_AS_PROOF) ? Py_True : Py_False);
if (id == NULL || entry == NULL) {
Py_XDECREF(id);
Py_XDECREF(entry);
Py_XDECREF(result);
Py_INCREF(Py_None);
return Py_None;
}
PyDict_SetItem(result, id, entry);
}
return result;
}
@ -967,6 +967,8 @@ _profile_getattr(CmsProfileObject* self, cmsInfoType field)
static PyObject*
cms_profile_getattr_product_desc(CmsProfileObject* self, void* closure)
{
PyErr_WarnEx(PyExc_DeprecationWarning,
"product_desc is deprecated. Use Unicode profile_description instead.", 1);
// description was Description != 'Copyright' || or "%s - %s" (manufacturer, model) in 1.x
return _profile_getattr(self, cmsInfoDescription);
}
@ -976,24 +978,32 @@ cms_profile_getattr_product_desc(CmsProfileObject* self, void* closure)
static PyObject*
cms_profile_getattr_product_description(CmsProfileObject* self, void* closure)
{
PyErr_WarnEx(PyExc_DeprecationWarning,
"product_description is deprecated. Use Unicode profile_description instead.", 1);
return _profile_getattr(self, cmsInfoDescription);
}
static PyObject*
cms_profile_getattr_product_model(CmsProfileObject* self, void* closure)
{
PyErr_WarnEx(PyExc_DeprecationWarning,
"product_model is deprecated. Use Unicode model instead.", 1);
return _profile_getattr(self, cmsInfoModel);
}
static PyObject*
cms_profile_getattr_product_manufacturer(CmsProfileObject* self, void* closure)
{
PyErr_WarnEx(PyExc_DeprecationWarning,
"product_manufacturer is deprecated. Use Unicode manufacturer instead.", 1);
return _profile_getattr(self, cmsInfoManufacturer);
}
static PyObject*
cms_profile_getattr_product_copyright(CmsProfileObject* self, void* closure)
{
PyErr_WarnEx(PyExc_DeprecationWarning,
"product_copyright is deprecated. Use Unicode copyright instead.", 1);
return _profile_getattr(self, cmsInfoCopyright);
}
@ -1006,12 +1016,16 @@ cms_profile_getattr_rendering_intent(CmsProfileObject* self, void* closure)
static PyObject*
cms_profile_getattr_pcs(CmsProfileObject* self, void* closure)
{
PyErr_WarnEx(PyExc_DeprecationWarning,
"pcs is deprecated. Use padded connection_space instead.", 1);
return PyUnicode_DecodeFSDefault(findICmode(cmsGetPCS(self->profile)));
}
static PyObject*
cms_profile_getattr_color_space(CmsProfileObject* self, void* closure)
{
PyErr_WarnEx(PyExc_DeprecationWarning,
"color_space is deprecated. Use padded xcolor_space instead.", 1);
return PyUnicode_DecodeFSDefault(findICmode(cmsGetColorSpace(self->profile)));
}
@ -1071,7 +1085,7 @@ cms_profile_getattr_creation_date(CmsProfileObject* self, void* closure)
}
return PyDateTime_FromDateAndTime(1900 + ct.tm_year, ct.tm_mon, ct.tm_mday,
ct.tm_hour, ct.tm_min, ct.tm_sec, 0);
ct.tm_hour, ct.tm_min, ct.tm_sec, 0);
}
static PyObject*
@ -1296,7 +1310,7 @@ cms_profile_getattr_green_primary(CmsProfileObject* self, void* closure)
result = _calculate_rgb_primaries(self, &primaries);
if (! result) {
Py_INCREF(Py_None);
return Py_None;
return Py_None;
}
return _xyz_py(&primaries.Green);
@ -1312,7 +1326,7 @@ cms_profile_getattr_blue_primary(CmsProfileObject* self, void* closure)
result = _calculate_rgb_primaries(self, &primaries);
if (! result) {
Py_INCREF(Py_None);
return Py_None;
return Py_None;
}
return _xyz_py(&primaries.Blue);
@ -1395,11 +1409,11 @@ cms_profile_getattr_icc_measurement_condition (CmsProfileObject* self, void* clo
geo = "unknown";
return Py_BuildValue("{s:i,s:(ddd),s:s,s:d,s:s}",
"observer", mc->Observer,
"backing", mc->Backing.X, mc->Backing.Y, mc->Backing.Z,
"geo", geo,
"flare", mc->Flare,
"illuminant_type", _illu_map(mc->IlluminantType));
"observer", mc->Observer,
"backing", mc->Backing.X, mc->Backing.Y, mc->Backing.Z,
"geo", geo,
"flare", mc->Flare,
"illuminant_type", _illu_map(mc->IlluminantType));
}
static PyObject*
@ -1420,9 +1434,9 @@ cms_profile_getattr_icc_viewing_condition (CmsProfileObject* self, void* closure
}
return Py_BuildValue("{s:(ddd),s:(ddd),s:s}",
"illuminant", vc->IlluminantXYZ.X, vc->IlluminantXYZ.Y, vc->IlluminantXYZ.Z,
"surround", vc->SurroundXYZ.X, vc->SurroundXYZ.Y, vc->SurroundXYZ.Z,
"illuminant_type", _illu_map(vc->IlluminantType));
"illuminant", vc->IlluminantXYZ.X, vc->IlluminantXYZ.Y, vc->IlluminantXYZ.Z,
"surround", vc->SurroundXYZ.X, vc->SurroundXYZ.Y, vc->SurroundXYZ.Z,
"illuminant_type", _illu_map(vc->IlluminantType));
}