I'm really used to statically type language hence ...
# general
b
I'm really used to statically type language hence I'm a bit lost when I see an argument passed around and want to know its type. For exemple with the context, I managed to find a reference here https://www.pantsbuild.org/dev_tasks.html but in a more general way how do you procede ? you just run and print ?
e
Having some sort of editor setup with python smarts is fairly invaluable. You get enough typing back to be able to navigate and comprehend fairly easily. I personally use IDEAs python support for this. As far as options go, you'll get more hits for examples grepping
self.get_options()
- an instance method of
Task
and the classmethod
register_options
- which is the pair. You can get a rich set of examples closely tracking what you're doing with the following in the Pants repo:
$ git grep SimpleCodegenTask | cut -d: -f1 | sort -u | xargs grep "def register_options(" | cut -d: -f1 | sort -u | xargs grep "self.get_options()"
As far as diamonds go, you can stay out of the woods and not think about them if you follow examples like you have and inherit from mixins first and then finally a single concrete super class, ei:
class MyTask(Mixin1, Mixin2, Task):
.
b
Thank you ! Actually I'm using intellij and yes the code exploration tool is invaluable but I can go from a variable usage to its declaration but then to find its type I'm stuck … So I went for the execute and print aproach Is there a language construct for mixin or is it just a convention where I reconize a mixin because the class is called
XXXMixin
?
About my task in particular, I'm not sure how to handle the diamond problem. This is semantically a CodeGenerator task but the implementation details is to run Javac. I tried to run the following code to get some insight :
Copy code
class QueryDslGen(SimpleCodegenTask, JavacCompile):
        
    def __init__(self, *args, **kwargs):
        super(QueryDslGen, self).__init__(*args, **kwargs)

    def synthetic_target_type(self, target):
        return JavaLibrary

    def is_gentarget(self, target):
        return isinstance(target, QueryDslLibrary)

    def execute(self):
        return super(SimpleCodegenTask).execute()

    def execute_codegen(self, target, target_workdir):
        if not isinstance(target, QueryDslLibrary):
            raise TaskError('Invalid target type "{class_type}" (expected QueryDslLibrary)'
                            .format(class_type=type(target).__name__))

        <http://self.context.log.info|self.context.log.info>('toto')
        <http://self.context.log.info|self.context.log.info>(self.context)


        result = 1

        if result != 0:
            raise TaskError('twirl-gen ... exited non-zero ({code})'.format(code=result))
but then I have a cycle detected :
Copy code
Exception caught: (<class 'pants.engine.round_engine.GoalCycleError'>)
                                      
Exception message: Cycle detected in goal dependencies:                                                                                                                                                                                       
        gen <- [resolve]        
        resolve <- [gen]                                                                                                                                                                                                                      
        deferred-sources <- [gen]
        imports <- [gen, unpack-jars]
        bootstrap <- [resolve, gen, imports]                                                                                                                                                                                                  
        jvm-platform-validate <- [resolve, gen]
        unpack-jars <- [deferred-sources]
So I tried to delegate the compilation part :
Copy code
class QueryDslGen(SimpleCodegenTask):

    compiler_delegate = None

    def __init__(self, *args, **kwargs):
        super(QueryDslGen, self).__init__(*args, **kwargs)
        compiler_delegate = JavacCompile(*args, **kwargs)

    def synthetic_target_type(self, target):
        return JavaLibrary

    def is_gentarget(self, target):
        return isinstance(target, QueryDslLibrary)

    def execute_codegen(self, target, target_workdir):
        if not isinstance(target, QueryDslLibrary):
            raise TaskError('Invalid target type "{class_type}" (expected QueryDslLibrary)'
                            .format(class_type=type(target).__name__))

        <http://self.context.log.info|self.context.log.info>('toto')
        <http://self.context.log.info|self.context.log.info>(self.context)


        result = 1

        if result != 0:
            raise TaskError('twirl-gen ... exited non-zero ({code})'.format(code=result))
but now I have the following error :
Copy code
Exception caught: (<type 'exceptions.NotImplementedError'>)

Exception message: <class 'pants.backend.jvm.tasks.jvm_compile.javac.javac_compile.JavacCompile'> must set an options_scope class-level property.
e
OK. Tasks are linked in an extra-lingual graph. They cannot be used except via that graph. IOW a task cannot directly call another task, whether via inheritance or composition. On the task graph side, broadly, in the current Pants engine, code is generated before compilation - full stop; ie JavacCompile expects generated code to be already available as a product in self.context.products. So you can't use JavacCompile at all in your codegen task, you need to hand-roll finding the compiler and calling it. You'll want to leverage the Subsystems that JavacCompile depends on (see the
subsystem_dependencies
classmethod of JavacCompile and it's hierarchy). Subsystems, unlike tasks, can be called directly. Even with this there is likely a good bit of logic to tie together the subsystems to get a compile.
b
thank you ! at least I know I was going in the wrong direction. Let's dig in subsystems !
about intellij idea and python how do you configure idea to recognize the absolute import within your module ?
for example in this project, in this file https://github.com/thesamet/play-pants/blob/master/src/python/play/tasks/routes_gen.py line 15 & 16 have red squiggles
e
Did you mark the
src/python
folder in the left hand pane view as a 'Sources Root'?
The left hand pane 'Project' view.
b
yay ! it's working
I was not in this exact setup, what is the source root was the module root and it seems it cannot be both
after creating a module one step above, all works fine ! let's do some python !
thank you
e
You're welcome!
h
@brief-engineer-67497 once we finish migrating to Python 3 this next month, we’ll be introducing Python type hints to the codebase! This will make it far easier to understand the code as you’re requesting
👍 2
b
Nice !