enthought / apptools

Other
37 stars 24 forks source link

Preferences can't be unset if they are the only one on a given node. #312

Open nicolasap-dm opened 2 years ago

nicolasap-dm commented 2 years ago

From the IPreference documentation, it's unclear to me whether I should use preferences.clear(key) or preferences.remove(key) to un-set a preference.

However, it looks as though neither works.

Is it possible to remove a preference altogether? And if so, should one of these two methods work to that end?

Expected

For preferences that are stored to file, if there is a preference at some key (namespace.key), it should be possible to remove that preference altogether.

Consider this initial situation:

>>> def cat(fname):
...     with open(fname, "r") as f:
...         print(f.read())
... 
>>> preferences = Preferences(filename="example.ini")
>>> preferences.set("namespace.field", "value")
>>> preferences.flush()
>>> cat("example.ini")
[namespace]
field = value

I would expect that

preferences.remove("namespace.field")
preferences.flush()

would result in a empty example.ini file.

Observed

Neither approach works:

>>> preferences.remove("namespace.field")
>>> preferences.flush()
>>> cat("example.ini")
[namespace]
field = value

>>> preferences.clear("namespace.field")
>>> preferences.flush()
>>> cat("example.ini")
[namespace]
field = value
nicolasap-dm commented 2 years ago

Note: I have just observed that only the last remaining preference of a namespace can't be removed.

If there is an existing other field in the same namespace, then the other field can be removed.

>>> preferences.set("namespace.field", "value")
>>> preferences.set("namespace.other_field", "other_value")
>>> preferences.flush()
>>> cat("example.ini")
[namespace]
field = value
other_field = other_value

>>> preferences.remove("namespace.field")
>>> preferences.flush()
>>> cat("example.ini")
[namespace]
other_field = other_value

I'm not sure if this limitation is expected, but it doesn't seem to be documented in the apidocs.

The general docs don't cover removing/un-setting preferences.


I'm updating the issue name.

nicolasap-dm commented 2 years ago

The behavior is actually particularly odd if, on the same preferences object, another field is added after the attempted removal of the initially only field.

At first, removing the only field doesn't work. But then, if another field is added, the previous remove operation takes effect.

>>> preferences = Preferences(filename="example.ini")
>>> preferences.set("namespace.field", "value")
>>> preferences.flush()
>>> cat("example.ini")
[namespace]
field = value

>>> preferences.remove("namespace.field")
>>> cat("example.ini")
[namespace]
field = value

>>> preferences.set("namespace.other_field", "other_value")
>>> preferences.flush()
>>> cat("example.ini")
[namespace]
other_field = other_value

>>> # NOTE: this operation appears to have both added a field and
>>> # removed another field from the file (which was not done before).

To summarize: it seems like the Preferences don't want to have empty namespaces on file (not sure if that's a .ini limitation), so they won't remove the last remaining field from a namespace.

However, the object will have registered that removal (unbekownst to the user) and may still "apply" it on a subsequent flush() if other conditions have changed.

Both the discrepancy between the state of the file and the state of the object, and the undocumented limitation, should be addressed. In general, key removal should be documented in the main Preferences docs.