So in Tor's python module, Stem, I can add hidden services, replace hidden services, etc. However! I cannot remove ALL hidden services. I do not know the magic magicness that does this... I've tried setting 'HiddenServiceDir/HiddenServicePort' and 'HiddenServiceOptions' to empty strings, empty lists and None. The only thing that does anything is setting 'HiddenServiceOptions' to None... which just brings back the last successful hidden service setting.... meaning that probably everything in between was just a bunk setting and I magically flipped a reset from tor control...
For example, here I start with a hidden service, then replace it with one or two more...
>>> controller.is_authenticated()
True
>>> controller.get_conf_map('HiddenServiceOptions')
{'HiddenServiceDir': ['/tmp/hiddenservice1/'],
'HiddenServicePort': ['1234 127.0.0.1:1234']}
>>> controller.set_options([('HiddenServiceDir','/tmp/hiddenservice2/'),('HiddenServicePort','1235 127.0.0.1:1235'),('HiddenServiceDir','/tmp/hiddenservice3/'),('HiddenServicePort','1236 127.0.0.1:1236')])
>>> controller.get_conf_map('HiddenServiceOptions')
{'HiddenServiceDir': ['/tmp/hiddenservice2/', '/tmp/hiddenservice3/'],
'HiddenServicePort': ['1235 127.0.0.1:1235', '1236 127.0.0.1:1236']}
>>> controller.set_options([('HiddenServiceDir','/tmp/hiddenservice3/'),('HiddenServicePort','1236 127.0.0.1:1236')])
>>> controller.get_conf_map('HiddenServiceOptions')
{'HiddenServiceDir': ['/tmp/hiddenservice3/'],
'HiddenServicePort': ['1236 127.0.0.1:1236']}
...and now the fun... I try to get rid of ALL hidden services...
>>> controller.set_options([('HiddenServiceDir',None),('HiddenServicePort',None)])
### *OR*
>>> controller.set_options([('HiddenServiceDir',''),('HiddenServicePort','')])
### .... and the result is....
>>> controller.get_conf_map('HiddenServiceOptions')
{'HiddenServiceOptions': []}
### ... nothing, as expected... but then...
>>> controller.set_options([('HiddenServiceDir','/tmp/hiddenservice3/'),('HiddenServicePort','1236 127.0.0.1:1236')])
>>> controller.get_conf_map('HiddenServiceOptions')
{'HiddenServiceOptions': []}
### ... hidden service not showing again... until...
>>> controller.set_options([('HiddenServiceOptions',None)])
>>> controller.get_conf_map('HiddenServiceOptions')
{'HiddenServiceDir': ['/tmp/hiddenservice3/'],
'HiddenServicePort': ['1236 127.0.0.1:1236']}
### ... suprise! It's back!
Funny thing, though... From checking my TOR connection in other ways, I can tell that my services were never all removed. They just stayed at whatever the last hidden service(s) I set...
... so I could keep spinning my wheels or search for valhalla in the source code... or maybe some enlightened soul can inform me... how do I get rid of my hidden services in stem?!
UPDATE
The problem seems to be a bug in how "HiddenServiceOptions" updates itself.
With a hidden service enabled, when I set both HiddenServiceDir and HiddenServicePort to None (or to empty strings; both have the exact same effect), it shows in my conf_map and I see a conf event sent out (from a listener on my controller) with configuration {'HiddenServiceOptions':None} (or as parsed_content, just 'HiddenServiceOptions' with no equal sign or anything). This is as expected.
...NOW, if I set another hidden service, I get a new configuration event sent to me showing the correct hidden service info. At this point, the hidden service WORKS, BUT it still won't show if I ask it with "get_conf_map".
Then I run reset_conf and it shows fine again.
The takeaway: if you setup a new service, first check if there are none. If so, set the hidden service, then run reset_conf...
Or for people who only rely on event_listeners, this doesn't affect them at all...
Thanks, Damian...