def __init__(self, **parameters: tp.Any) -> None: super().__init__() self._content: tp.Dict[tp.Any, Parameter] = {k: as_parameter(p) for k, p in parameters.items()} self._sizes: tp.Optional[tp.Dict[str, int]] = None self._sanity_check(list(self._content.values())) self._ignore_in_repr: tp.Dict[ str, str ] = {} # hacky undocumented way to bypass boring representations
def apply(self, method: str, *args: tp.Any, **kwargs: tp.Any) -> tp.Dict[tp.Any, tp.Any]: """Calls the named method with the provided input parameters (or their subobjects if from the base class!) on the subobjects. """ outputs: tp.Dict[tp.Any, tp.Any] = {} for key, subobj in self.items(): subargs = [self._get_subobject(arg, key) for arg in args] subkwargs = {k: self._get_subobject(kwarg, key) for k, kwarg in kwargs.items()} outputs[key] = getattr(subobj, method)(*subargs, **subkwargs) return outputs
def __init__(self, **parameters: tp.Any) -> None: super().__init__() self._subobjects = utils.Subobjects(self, base=core.Parameter, attribute="_content") self._content: tp.Dict[tp.Any, core.Parameter] = { k: core.as_parameter(p) for k, p in parameters.items() } self._sizes: tp.Optional[tp.Dict[str, int]] = None self._sanity_check(list(self._content.values())) self._ignore_in_repr: tp.Dict[ str, str ] = {} # hacky undocumented way to bypass boring representations
def __call__(self, *args: tp.Any, **kwargs: tp.Any) -> str: """Call the cammand line with addidional arguments The keyword arguments will be sent as --{key}={val} The logs are bufferized. They will be printed if the job fails, or sent as output of the function Errors are provided with the internal stderr """ # TODO make the following command more robust (probably fails in multiple cases) full_command = (self.command + [str(x) for x in args] + ["--{}={}".format(x, y) for x, y in kwargs.items()]) if self.verbose: print(f"The following command is sent: {full_command}") outlines: tp.List[str] = [] with subprocess.Popen( full_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False, cwd=self.cwd, env=self.env, ) as process: try: assert process.stdout is not None for line in iter(process.stdout.readline, b""): if not line: break outlines.append(line.decode().strip()) if self.verbose: print(outlines[-1], flush=True) except Exception: # pylint: disable=broad-except process.kill() process.wait() raise FailedJobError("Job got killed for an unknown reason.") stderr = process.communicate()[1] # we already got stdout stdout = "\n".join(outlines) retcode = process.poll() if stderr and (retcode or self.verbose): print(stderr.decode(), file=sys.stderr) if retcode: subprocess_error = subprocess.CalledProcessError(retcode, process.args, output=stdout, stderr=stderr) raise FailedJobError(stderr.decode()) from subprocess_error return stdout