Patchwork [1,of,2,v3] config: add hasconfig method and supporting plumbing

login
register
mail settings
Submitter Bryan O'Sullivan
Date Jan. 8, 2016, 4:50 p.m.
Message ID <8b71747150c066ba5244.1452271831@bryano-mbp.local>
Download mbox | patch
Permalink /patch/12601/
State Accepted
Delegated to: Yuya Nishihara
Headers show

Comments

Bryan O'Sullivan - Jan. 8, 2016, 4:50 p.m.
# HG changeset patch
# User Bryan O'Sullivan <bos@serpentine.com>
# Date 1452224703 28800
#      Thu Jan 07 19:45:03 2016 -0800
# Node ID 8b71747150c066ba5244adf88edff406c30db94c
# Parent  c1a5661327730550ddee47125ef090fbebcaeb11
config: add hasconfig method and supporting plumbing

The ui.config method makes it impossible to distinguish between a
config value that was never supplied and one that is empty.  You
might hope that you could write something like this:

  unspecified = object()
  val = ui.config('section', 'thingy', default=unspecified)

Sadly, this will happily return unspecified regardless of whether no
value was provided or an empty value was specified.

We add the hasconfig method to make it possible to distinguish the
two cases.
Yuya Nishihara - Jan. 9, 2016, 8:08 a.m.
On Fri, 08 Jan 2016 08:50:31 -0800, Bryan O'Sullivan wrote:
> # HG changeset patch
> # User Bryan O'Sullivan <bos@serpentine.com>
> # Date 1452224703 28800
> #      Thu Jan 07 19:45:03 2016 -0800
> # Node ID 8b71747150c066ba5244adf88edff406c30db94c
> # Parent  c1a5661327730550ddee47125ef090fbebcaeb11
> config: add hasconfig method and supporting plumbing
> 
> The ui.config method makes it impossible to distinguish between a
> config value that was never supplied and one that is empty.  You
> might hope that you could write something like this:
> 
>   unspecified = object()
>   val = ui.config('section', 'thingy', default=unspecified)
> 
> Sadly, this will happily return unspecified regardless of whether no
> value was provided or an empty value was specified.

No, it should return unspecified only if no value was provided, i.e.
val is None.

I guess you've tried something like the following. It doesn't work because
of addr = ('' or None).

  addr = (ui.config('email', configkey) or
          ui.config('patchbomb', configkey))
  if addr is None and ask:
      addr = prompt(ui, header, default=default)

On the other hand, this should work:

  addr = ui.config('patchbomb', configkey, ui.config('email', configkey))

That said, ui.hasconfig() should be less error-prone than testing '' and None.
I'll queue this series with tweaking the commit message. Many thanks.
Bryan O'Sullivan - Jan. 11, 2016, 5:21 p.m.
On Sat, Jan 9, 2016 at 12:08 AM, Yuya Nishihara <yuya@tcha.org> wrote:

> > Sadly, this will happily return unspecified regardless of whether no
> > value was provided or an empty value was specified.
>
> No, it should return unspecified only if no value was provided, i.e.
> val is None.
>

Maybe that's what it *should* do, but I am describing what it actually does
today :-)
Matt Mackall - Jan. 11, 2016, 10:28 p.m.
On Mon, 2016-01-11 at 09:21 -0800, Bryan O'Sullivan wrote:
> On Sat, Jan 9, 2016 at 12:08 AM, Yuya Nishihara <yuya@tcha.org> wrote:
> 
> > > Sadly, this will happily return unspecified regardless of whether no
> > > value was provided or an empty value was specified.
> > 
> > No, it should return unspecified only if no value was provided, i.e.
> > val is None.
> > 
> 
> Maybe that's what it *should* do, but I am describing what it actually does
> today :-)

Works for me:

$ hg dbsh
loaded repo : /home/mpm/hg
using source: /home/mpm/hg/mercurial
>>> repo.ui.config("ui", "username", object())
'Matt Mackall <mpm@selenic.com>'
>>> repo.ui.config("ui", "petname", object())
<object object at 0x7f8207912100>
>>> repo.ui.config("ui", "username", False) == False
False
>>> repo.ui.config("ui", "petname", False) == False
True

-- 
Mathematics is the supreme nostalgia of our time.

Patch

diff --git a/mercurial/config.py b/mercurial/config.py
--- a/mercurial/config.py
+++ b/mercurial/config.py
@@ -30,6 +30,8 @@  class config(object):
         return config(self)
     def __contains__(self, section):
         return section in self._data
+    def hasitem(self, section, item):
+        return item in self._data.get(section, {})
     def __getitem__(self, section):
         return self._data.get(section, {})
     def __iter__(self):
diff --git a/mercurial/ui.py b/mercurial/ui.py
--- a/mercurial/ui.py
+++ b/mercurial/ui.py
@@ -281,6 +281,9 @@  class ui(object):
                                "%s.%s = %s\n" % (section, n, uvalue))
         return value
 
+    def hasconfig(self, section, name, untrusted=False):
+        return self._data(untrusted).hasitem(section, name)
+
     def configsuboptions(self, section, name, default=None, untrusted=False):
         """Get a config option and all sub-options.