Search code examples
pythonsetattrluigi

calling setattr before 'self' is returned


I suspect this is kind of a klugefest on my part, but I'm working with the Luigi and Sciluigi modules which set a number of critical parameters PRIOR to 'self' being returned by an init. ANd if I try to manhandle these parameters AFTER self is returned, the Luigi.Parameter object masks them in such a way that I cant do what I need to do.

The luigi and sciluigi classes (as one uses them) contain no __init__. And if I try to insert an __init__ or call super(ChildClass, self).__init__(*args, **kwargs) ...I get weird errors 'unexpected parameter' errors.

So a Sciluigi class looks like this...

class MyTask(sciluigi.task):
    param1 = sciluigi.Parameter(default='Yes') #String only
    param2 = sciluigi.Parameter(default='No')  #String only

    def out_target(self):
        return sciluigi.TargetInfo(self, self.out)

    def run(self):
        with self.out_target().open('w') as foofile:
            foofile.write('foo\n')

SO...I'm hoping I can dynamically set some parameters via setattr PRIOR to 'self' actually being returned. But setattr requires the object.

I was hoping I could do something like...

setattr(inspect.stack()[?][?], 'DynamicVar', sciluigi.Parameter(default='Yes') )

EDIT: @Charles Duffy

Well, I'm not sure what info would be most helpful.

First issue is; I can't add an init. The actual code is below, with an __init__method added. I've included the resulting error if I try to run it. Its the same error is if I tr to run the super call to __init__

class FileConverter(sciluigi.Task):
    """
    """
    in_target   = None # Mandatory
    out = sciluigi.Parameter() # <file>
    exepath = sciluigi.Parameter(default = "") 

    def __init__(self):
        self.var = 'anything'

    def out_target(self):
        log.debug("In 'FileConverter.out_target'... ")
        return sciluigi.TargetInfo(self, self.out)

    def run(self):
        result = None
        command = ''.join([
                           self.exepath, _slash, "FileConverter ",
                           " -in ", self.in_target().path,
                           " -out ", self.out_target().path, 
                           " -out_type ", self.file_type
                           ])
        log.info("RUNNING COMMAND: " + command)
        result = self.ex(command)
        log.info("result: " + result[1])

Error

2017-02-24 17:01:48 |  WARNING | Will not run MyWorkflow(instance_name=sciluigi_workflow) or any dependencies due to error in deps() method:
Traceback (most recent call last):
  File "/Library/Python/2.7/site-packages/luigi/worker.py", line 697, in _add
    deps = task.deps()
  File "/Library/Python/2.7/site-packages/luigi/task.py", line 572, in deps
    return flatten(self._requires())
  File "/Library/Python/2.7/site-packages/luigi/task.py", line 544, in _requires
    return flatten(self.requires())  # base impl
  File "/Library/Python/2.7/site-packages/sciluigi/workflow.py", line 105, in requires
    workflow_output = self.workflow()
  File "/Users/mikes/Documents/Eclipseworkspace/Bioproximity/OpenMS-Python-Luigi/site-packages/Bioproximity/sciluigi_tasks/PipelineTest1.py", line 33, in workflow
    exepath = "/Applications/OpenMS-2.1.0/TOPP"
  File "/Library/Python/2.7/site-packages/sciluigi/workflow.py", line 145, in new_task
    newtask = sciluigi.new_task(instance_name, cls, self, **kwargs)
  File "/Library/Python/2.7/site-packages/sciluigi/task.py", line 37, in new_task
    newtask = cls.from_str_params(kwargs)
  File "/Library/Python/2.7/site-packages/luigi/task.py", line 412, in from_str_params
    return cls(**kwargs)
  File "/Library/Python/2.7/site-packages/luigi/task_register.py", line 99, in __call__
    h[k] = instantiate()
  File "/Library/Python/2.7/site-packages/luigi/task_register.py", line 80, in instantiate
    return super(Register, cls).__call__(*args, **kwargs)
TypeError: __init__() got an unexpected keyword argument 'instance_name'

The second issue is:

If I wait for self to return, I can no longer differentiate between (for example using the above code)...

in_target   = None # Mandatory
out = sciluigi.Parameter() # <file>

If I do a type(out), type reports that the parameter is just a string (not a sciluigi.Parameter object) so if I try to use a `ìsinstance(out, sciluigi.Parameter)...it returns False.

The bottom line is:

I need to be able to set the sciluigi.Parameter objects dynamically (programatically) and subsequently be able to differentiate between a sciluigi.Parameter() object variable (like out) and a 'real' str() object (like in_target)

I hope this makes sense.


Solution

  • Just for future reference, the answer to the isolated question, "How to...

    setattr(<thisClassObject>, 'DynamicVar', sciluigi.Parameter(default='Yes') )
    

    Is to use the locals() built in function. I.e.

    locals()['DynamicVar'] = sciluigi.Parameter(default='Yes') #String only
    

    This is a snippet of how I solved my particular kluge ;)

    deleteme.py

    import sciluigi
    
    class MyFooWriter(sciluigi.Task):
        locals()['outfile'] = sciluigi.Parameter(default='./foo.txt') #String only
        locals()['normalvar'] = 'Normalstring'
        print "pre-self-returned outfile type =", type(outfile)
        print "pre-self-returned normalvar type =", type(normalvar)
    #     locals()['param1'] = 
        def out_foo(self):
            # raw_input("Enter...")
            return sciluigi.TargetInfo(self, self.outfile)
    
        def run(self):
            print "self.outfile type =", type(self.outfile)
            print "self.normalvar type =", type(self.normalvar)
            # raw_input("Enter...")        
            with self.out_foo().open('w') as foofile:
                foofile.write('foo\n')            
    
    
    class MyWorkflow(sciluigi.WorkflowTask):
        def workflow(self):
            print 'Starting workflow...'
            foowriter = self.new_task('foowriter', MyFooWriter, outfile = 'testfile.txt')
            return foowriter        
    
    if __name__ == '__main__':
        sciluigi.run_local(main_task_cls=MyWorkflow)  
    

    OUTPUT

    pre-self-returned outfile type = <class 'sciluigi.parameter.Parameter'>
    pre-self-returned normalvar type = <type 'str'>
    Starting workflow...
    2017-02-27 12:08:37 |     INFO | --------------------------------------------------------------------------------
    2017-02-27 12:08:37 |     INFO | SciLuigi: MyWorkflow Workflow Started (logging to log/workflow_myworkflow_started_20170227_110837_278707.log)
    2017-02-27 12:08:37 |     INFO | --------------------------------------------------------------------------------
    2017-02-27 12:08:37 |     INFO | Task foowriter started
    self.outfile type = <type 'str'>
    self.normalvar type = <type 'str'>
    2017-02-27 12:08:37 |     INFO | Task foowriter finished after 0.001s
    Starting workflow...
    2017-02-27 12:08:37 |     INFO | --------------------------------------------------------------------------------
    2017-02-27 12:08:37 |     INFO | SciLuigi: MyWorkflow Workflow Finished (workflow log at log/workflow_myworkflow_started_20170227_110837_278707.log)
    2017-02-27 12:08:37 |     INFO | --------------------------------------------------------------------------------