class_docstr: The abstract base class of experiment config classes.
  
  A config class should be a type-hinted dataclass inheriting ``ConfigBase``.
  Or for a training service config class, it can inherit ``TrainingServiceConfig``.
  
  .. code-block:: python
  
      @dataclass(init=False)
      class ExperimentConfig(ConfigBase):
          name: Optional[str]
          ...
  
  Subclasses are suggested to override ``_canonicalize()`` and ``_validate_canonical()`` methods.
  
  Users can create a config object with constructor or ``ConfigBase.load()``,
  validate its legality with ``ConfigBase.validate()``,
  and finally convert it to the format accepted by NNI manager with ``ConfigBase.json()``.
  
  Example usage:
  
  .. code-block:: python
  
      # when using Python API
      config1 = ExperimentConfig(trialCommand='...', trialConcurrency=1, ...)
      config1.validate()
      print(config1.json())
  
      # when using config file
      config2 = ExperimentConfig.load('examples/config.yml')
      config2.validate()
      print(config2.json())
  
  Config objects will remember where they are loaded; therefore relative paths can be resolved smartly.
  If a config object is created with constructor, the base path will be current working directory.
  If it is loaded with ``ConfigBase.load(path)``, the base path will be ``path``'s parent.
  
  .. attention::
  
      All the classes that inherit ``ConfigBase`` are not allowed to use ``from __future__ import annotations``,
      because ``ConfigBase`` uses ``typeguard`` to perform runtime check and it does not support lazy annotations.
class_docstr_tok: ["The","abstract","base","class","of","experiment","config","classes",".","A","config","class","should","be","a","type-hinted","dataclass","inheriting","``","ConfigBase","``",".","Or","for","a","training","service","config","class",",","it","can","inherit","``","TrainingServiceConfig","``",".","..","code-block",":",":","python","@","dataclass","(","init=False",")","class","ExperimentConfig","(","ConfigBase",")",":","name",":","Optional","[","str","]","...","Subclasses","are","suggested","to","override","``","_canonicalize","(",")","``","and","``","_validate_canonical","(",")","``","methods",".","Users","can","create","a","config","object","with","constructor","or","``","ConfigBase.load","(",")","``",",","validate","its","legality","with","``","ConfigBase.validate","(",")","``",",","and","finally","convert","it","to","the","format","accepted","by","NNI","manager","with","``","ConfigBase.json","(",")","``",".","Example","usage",":","..","code-block",":",":","python","#","when","using","Python","API","config1","=","ExperimentConfig","(","trialCommand=","'","...","'",",","trialConcurrency=1",",","...",")","config1.validate","(",")","print","(","config1.json","(",")",")","#","when","using","config","file","config2","=","ExperimentConfig.load","(","'examples\/config.yml","'",")","config2.validate","(",")","print","(","config2.json","(",")",")","Config","objects","will","remember","where","they","are","loaded",";","therefore","relative","paths","can","be","resolved","smartly",".","If","a","config","object","is","created","with","constructor",",","the","base","path","will","be","current","working","directory",".","If","it","is","loaded","with","``","ConfigBase.load","(","path",")","``",",","the","base","path","will","be","``","path","``","'s","parent",".","..","attention",":",":","All","the","classes","that","inherit","``","ConfigBase","``","are","not","allowed","to","use","``","from","__future__","import","annotations","``",",","because","``","ConfigBase","``","uses","``","typeguard","``","to","perform","runtime","check","and","it","does","not","support","lazy","annotations","."]
docstr: To be overrided by subclass.
  
  Convert the config object to canonical format.
  
  The default implementation will:
  
  1. Resolve all ``PathLike`` fields to absolute path
  2. Call ``_canonicalize([self] + parents)`` on all children config objects, including those inside list and dict
  
  If the subclass has nested config fields, be careful about where to call ``super()._canonicalize()``.
  
  Parameters
  ----------
  parents : list[ConfigBase]
      The upper level config objects.
      For example local training service's ``trialGpuNumber`` will be copied from top level when not set,
      in this case it will be invoked like ``localConfig._canonicalize([experimentConfig])``.
docstr_tok: ["To","be","overrided","by","subclass",".","Convert","the","config","object","to","canonical","format",".","The","default","implementation","will",":","1",".","Resolve","all","``","PathLike","``","fields","to","absolute","path","2",".","Call","``","_canonicalize","(","[","self","]","+","parents",")","``","on","all","children","config","objects",",","including","those","inside","list","and","dict","If","the","subclass","has","nested","config","fields",",","be","careful","about","where","to","call","``","super","(",")","._canonicalize","(",")","``",".","Parameters","--","--","--","--","--","parents",":","list","[","ConfigBase","]","The","upper","level","config","objects",".","For","example","local","training","service","'s","``","trialGpuNumber","``","will","be","copied","from","top","level","when","not","set",",","in","this","case","it","will","be","invoked","like","``","localConfig._canonicalize","(","[","experimentConfig","]",")","``","."]
code: def _canonicalize(self, parents):
      """
      To be overrided by subclass.
  
      Convert the config object to canonical format.
  
      The default implementation will:
  
      1. Resolve all ``PathLike`` fields to absolute path
      2. Call ``_canonicalize([self] + parents)`` on all children config objects, including those inside list and dict
  
      If the subclass has nested config fields, be careful about where to call ``super()._canonicalize()``.
  
      Parameters
      ----------
      parents : list[ConfigBase]
          The upper level config objects.
          For example local training service's ``trialGpuNumber`` will be copied from top level when not set,
          in this case it will be invoked like ``localConfig._canonicalize([experimentConfig])``.
      """
      for field in utils.fields(self):
          value = getattr(self, field.name)
          if isinstance(value, (Path, str)) and utils.is_path_like(
              field.type
          ):
              setattr(
                  self,
                  field.name,
                  utils.resolve_path(value, self._base_path),
              )
          else:
              _recursive_canonicalize_child(value, [self] + parents)
  
file_path: nni/nni/experiment/config/base.py
imports: import copy
  import dataclasses
  from pathlib import Path
  import yaml
  from .None import utils
label_desc: Use image node_id 6 for calling the ConfigBase obj's underlying member method code with example usage: obj._canonicalize(parents) without return types