docs: def FromSpec(self, spec):
          """
          Args:
            spec: (name, {...}), or Parameter object
  
          Dict keys:
            "caption" -- (optional) text for label in editor. Defaults to the
                   keyword argument name
            "toolTip" (optional)
            "type" -- (optional, defaults to type("value") or int if "value" is
                not specified. Accepts:
                  - int
                  - float
                  - str
                  - bool
                  - list
            "value" -- (optional) defaults to 1 if numeric, False if bool,
                 "" if str
  
          """
          if isinstance(spec, Parameter):
              self.name = spec.name
              self.caption = spec.caption if spec.caption is not None else spec.name
              self.toolTip = spec.toolTip if spec.toolTip is not None else ""
              self.type = spec.type if spec.type is not None else type(spec.value) if spec.value is not None else int
              self.value = spec.value
          else:
              self.name, d = spec
              self.caption = d.get("caption", self.name)
              self.toolTip = d.get("toolTip", "")
              t = self.type = d.get("type", type(d["value"]) if "value" in d else int)
              if not t in (int, float, bool, str, list):
                  raise TypeError("Invalid type: '{0!s}'".format(t.__name__))
              self.value = d.get("value")
  
          if self.value is None:
              self.value = 0 if self.type == int else \
                  0. if self.type == float else \
                  False if self.type == bool else ""