DotDict __getattr__hack. I wrote about that here.
For some reason I took another stab at it last week, after leveling up my python3 porting skills. I got the tests green, submitted a PR, which is now merged and released. Woot!
DotDict __getattr__hack. I wrote about that here.
I don't know how much demand there will be, if we do end up packaging these tools in a way that others can use them. But if we don't package them, we may never know. And I do know that there are entire companies built around shipping tools like these. We don't have to drop any existing goals on the floor to chase this dream, but I think it's worth pursuing in the future.
A few people have suggested I look at other packages for config solutions. I thought I'd record some of my thoughts on the matter. Let's look at requirements first.
diffand version control on these files is invaluable.
Argparse is the standardized python commandline argument parser, which is why configman and scriptharness have wrapped it to add further functionality. Its main drawbacks are lack of config file support and limited validation.
Namespace, and you have to use the
parser.get_default()method to determine whether it's a default value or an explicitly set commandline option.
requiredflag but not a
if foo is set, bar is requiredtype validation. It's possible to roll your own, but that would be script-specific rather than part of the standard.
argparse.Namespacewill take changes silently.
Configman is a tool written to deal with configuration in various forms, and adds the ability to transform configs from one type to another (e.g., commandline to ini file). It also adds the ability to block certain keys from being saved or output. Its argparse implementation is deeper than scriptharness' ConfigTemplate argparse abstraction.
Its main drawbacks for scriptharness usage appear to be lack of python 3 + py2-unicode-by-default support, and for being another non-standardized solution. I've given python3 porting two serious attempts, so far, and I've hit a wall on the dotdict
__getattr__ hack working differently on python 3. My wip is here if someone else wants a stab at it.
configman.namespace.Namespacewill take changes silently.
Docopt simplifies the commandline argument definition and prettifies the help output. However, it's purely a commandline solution, and doesn't support adding groups of commandline options together, so it appears to be oriented towards relatively simple script configuration. It could potentially be added to json-schema definition and validation, as could the argparse-based commandline solutions, for an all-in-two solution. More on that below.
This looks very promising for an overall config definition + validation schema. The main drawback, as far as I can see so far, is the lack of commandline argument support.
A commandline parser could generate a config object to validate against the schema. (Bonus points for writing a function to validate a parser against the schema before runtime.) However, this would require at least two definitions: one for the schema, one for the hopefully-compliant parser. Alternately, the schema could potentially be extended to support argparse settings for various items, at the expense of full standards compatiblity.
There's already a python jsonschema package.
Scriptharness currently extends
dict for its config. It checks off the most boxes in the requirements list currently. My biggest worry with the
ConfigTemplate is that it isn't fully standardized, so people may be hesitant to port all of their configs to it.
An argparse/json-schema solution with enough glue code in between might be a good solution. I think ConfigTemplate is sufficiently close to that that adding jsonschema support shouldn't be too difficult, so I'm leaning in that direction right now. Configman has some nice behind the scenes and cross-file-type support, but the python3 and __getattr__ issues are currently blockers, and it seems like a lateral move in terms of standards.
An alternate solution may be BYOC. If the scriptharness Script takes a config object that you built from somewhere, and gives you tools that you can choose to use to build that config, that may allow for enough flexibility that people can use their preferred style of configuration in their scripts. The cost of that flexibility is familiarity between scriptharness scripts.
execfileing python again, and PyYAML doesn't always install cleanly everywhere. It's on the list to add more formats, though. We probably need at least one dynamic type of config file (e.g. python or yaml) or a config-file builder tool.
LoggingDictthat logs runtime changes;
ReadOnlyDict(sams as mozharness) that prevents any changes after locking.
As far as I can tell there is no perfect solution here. Thoughts?
I've been getting some good feedback about scriptharness 0.1.0; thank you. I listed the 0.2.0 highlights and changes in the 0.2.0 Release Notes, but wanted to mention a few things here.
First, mozharness' config had the flexibility of accepting any arbitrary key/value pairs from various sources (initial_config, commandline options, config files...). However, it wasn't always clear what each config variable was for, or if it was required, or if the config was valid. I filed bug 699343 back in 2011, but didn't know how to tackle it then. I believe I have the solution now, with ConfigTemplates.
Second, 0.1.0 was definitely lacking a
get_output_from_command() analogs. 0.2.0 has
Command for just running+logging a command,
ParsedCommand for parsing the output of a command, and
Output for getting the output from a command, as well as
get_text_output() shortcut functions to instantiate the objects and run them for you. (Docs are here.) Each of these supports cross-platform
max_timeouts in both python 2.7 and python3, thanks to the multiprocessing module. As a bonus, I was able to add context line support to the
ParsedCommand. This was also a want since 2011.
I fleshed out some more documentation and populated the scriptharness issues with my todo list.
I think I know what I have in mind for 0.3.0, but feedback is definitely welcome!
I found myself missing mozharness at various points over the past 10 months. Several things kept me from using it at my then-new job:
mozharness.base.*largely non-Mozilla-specific, the mozharness clone-and-run model meant there was a lot of Mozilla-specific code that came along with it.
I had wanted to address these issues for years, but never had time to devote fully to harness-specific development.
Now I do.
Introducing scriptharness 0.1.0:
I'm proud of this. I'm also aware it's not mature [yet], and it's currently missing some functionality.
There are some ideas I'd love to explore before 1.0.0:
--add-action clobber --no-uploadstructure, or play with
--actions +clobber -uploador something. (The - before the upload in the latter might cause argparse issues?)
I already have 0.2.0 on the brain. I'd love any feedback or patches.