Reputation: 2492
So, this is a kluge. I'm working with luigi and sciluigi.
The isinstance
check is in the sciluigi package, and I'd rather kluge it then have to branch the entire sciluigi for this small issue :)
Simply put, I had to subclass one of the package's classes (luigi.LocalTarget)- to add additional functionality. THAT functionality works great, BUT there's an object check in the sciluigi package...
sciluigi.dependencies.DependencyHelpers._parse_outputitem()
...which causes the run to fail simply because an isinstance
line is set to check only for 'TargetInfo' objects.
What I'd LIKE to do is just tell my child class to 'lie' to isinstance
so it reports as a TargetInfo
object and passes :D
Forgiveness asked in advance :D
def _parse_outputitem(self, val, targets):
'''
Recursively loop through lists of TargetInfos, or
callables returning TargetInfos, or lists of ...
(repeat recursively) ... and return all targets.
'''
if callable(val):
val = val()
if isinstance(val, TargetInfo):
targets.append(val.target)
elif isinstance(val, list):
for valitem in val:
targets = self._parse_outputitem(valitem, targets)
elif isinstance(val, dict):
for _, valitem in iteritems(val):
targets = self._parse_outputitem(valitem, targets)
else:
raise Exception('Input item is neither callable, TargetInfo, nor list: %s' % val)
return targets
Error message:
2017-04-06 22:26:09,753 - PipeineTest1 - DEBUG - RunSubprocess:Traceback (most recent call last):
2017-04-06 22:26:09,754 - PipeineTest1 - DEBUG - RunSubprocess: File "/Library/Python/2.7/site-packages/luigi/worker.py", line 305, in check_complete
2017-04-06 22:26:09,754 - PipeineTest1 - DEBUG - RunSubprocess: is_complete = task.complete()
2017-04-06 22:26:09,754 - PipeineTest1 - DEBUG - RunSubprocess: File "/Library/Python/2.7/site-packages/luigi/task.py", line 482, in complete
2017-04-06 22:26:09,754 - PipeineTest1 - DEBUG - RunSubprocess: outputs = flatten(self.output())
2017-04-06 22:26:09,754 - PipeineTest1 - DEBUG - RunSubprocess: File "/Library/Python/2.7/site-packages/sciluigi/dependencies.py", line 99, in output
2017-04-06 22:26:09,754 - PipeineTest1 - DEBUG - RunSubprocess: return self._output_targets()
2017-04-06 22:26:09,755 - PipeineTest1 - DEBUG - RunSubprocess: File "/Library/Python/2.7/site-packages/sciluigi/dependencies.py", line 111, in _output_targets
2017-04-06 22:26:09,755 - PipeineTest1 - DEBUG - RunSubprocess: output_targets = self._parse_outputitem(attrval, output_targets)
2017-04-06 22:26:09,755 - PipeineTest1 - DEBUG - RunSubprocess: File "/Library/Python/2.7/site-packages/sciluigi/dependencies.py", line 132, in _parse_outputitem
2017-04-06 22:26:09,755 - PipeineTest1 - DEBUG - RunSubprocess: raise Exception('Input item is neither callable, TargetInfo, nor list: %s' % val)
2017-04-06 22:26:09,755 - PipeineTest1 - DEBUG - RunSubprocess:Exception: Input item is neither callable, TargetInfo, nor list: <Bioproximity.common.luigi_extensions.local_target.ToppasLocalTarget object at 0x110e48190>
...unfortunately, thats 100% of the error traceback that Sciluigi provides as output.
sciluigi.dependencies.TargetInfo(object)
class TargetInfo(object):
'''
Class to be used for sending specification of which target, from which
task, to use, when stitching workflow tasks' outputs and inputs together.
'''
task = None
path = None
target = None
def __init__(self, task, path, format=None, is_tmp=False):
self.task = task
self.path = path
self.target = luigi.LocalTarget(path, format, is_tmp)
def open(self, *args, **kwargs):
'''
Forward open method, from luigi's target class
'''
return self.target.open(*args, **kwargs)
# ==============================================================================
Upvotes: 3
Views: 246
Reputation: 104712
I think you need to create a TargetInfo
subclass in addition to the LocalTarget
subclass you already have. It looks like you're currently trying to use your current subclass as the former, when it is an instance of the latter. Passing an instance of your custom class doesn't work because passing a regular LocalTarget
in that same place wouldn't work either.
Try something like this:
class MyTargetInfo(TargetInfo): # pick your own name
def __init__(self, task, path, *args): # you might want to explicitly name the args here
self.task = task
self.path = path
self.target = ToppasLocalTarget(*args)
You'll want to pass an instance of this class to the function that was giving you errors when you gave it an instance of your LocalTarget
subclass. As I commented, you should give the class a better name, and perhaps name (and maybe give default values) to the arguments you need to pass on to your other class explicitly (rather than using *args
).
If constructing the target
within MyTargetInfo.__init__
is not a good match for your custom class's needs (e.g. you need to create it ahead of time or reuse the same instance several times), you could pass an already existing LocalTarget
into the constructor, and just assign it to self.target
instead of creating a new object. I don't know enough about the library you're using to judge if that's a good idea or not.
Upvotes: 2
Reputation: 1008
It looks like you just need to subclass TargetInfo
so that your object will pass the isinstance
check. You can have it like this:
class Foo(<whatever other base classes you have>, TargetInfo):
...
If you have TargetInfo
as the root descendant then it shouldn't interfere with the class's functionality because the other base classes will override any conflicting methods.
Upvotes: 1