0

I need to develop a demo ETL system that need to run from following fluent python format

ETL().source(source_args).sink(sink_args).run()

I made the class ETL() after this I made a function source and function sink in the class. Code looks like this:

class ETL:

    def source(self, data_source: str):
        if data_source == 'Simulation':
            simulation()
        elif data_source == 'File':
            main()

    def sink(self, data_sink: str):
        if data_sink == 'Console':
            command = 'Continue'
            user_command = input('Please type to Continue or to Stop!')
            while command != 'Stop':
                simulation()

        else:
            pass

ETL().source('Simulation').sink('Console')

When I run the file I receive this error:

AttributeError: 'NoneType' object has no attribute 'sink'

Where I am wrong and how to add the last method .run()? I take simulation() function from another file but this is not the problem.

quamrana
  • 37,849
  • 12
  • 53
  • 71
mikegrep
  • 27
  • 7

3 Answers3

4

I think the problem here is that your method source() does not return anything, so you recibe a None as ouput. Then when applying the second method (sink()) you are not doing it any more with an instance of ETL but with the output of ETL().source('Simulation'). You should try something like this:

foo = ETL()
foo.source('Simulation')
foo.sink('Console')

Another solution (although I don't think it's the best way to do this) is that you returned self in the source method. That would allow you to continue working with the instance of your class, and running the line of code you want.

  • Its need to be in following format ETL().source(source_args).sink(sink_args).run() – mikegrep Jun 25 '21 at 16:46
  • 2
    @mikegrep: but are you getting the clues that both these answers are pointing you to? – quamrana Jun 25 '21 at 16:47
  • 2
    If you really need it in that format then try adding `return self` in every method. I don't know what you're doing but I don't think this is a good solution to the problem. I just guess it might work anyway. – Diego Pereyra Jun 25 '21 at 16:51
  • Yes with `'return self` is working any advice how to implement and the wast method `run()` – mikegrep Jun 25 '21 at 16:56
3

NoneType means that instead of an instance of the ETL which you want to call, you've actually got None. That's because the function call failed or returned an unexpected result.

A way to change that would be to add a return to your functions.

The standard run() method invokes the callable object passed to the object's constructor as the target argument with sequential and keyword arguments taken from the args and kwargs arguments, respectively. Each time an object is created a method is called. That methods is named the constructor.

The constructor is created with the function init. As parameter we write the self keyword, which refers to itself (the object). The function init(self) builds your object. Its not just variables you can set here, you can call class methods too. Everything you need to initialize the object(s). It could look something like this:

def __init__(self):
       self.source()
       self.sink()
christheliz
  • 176
  • 2
  • 15
  • Sorry, but that still isn't the answer. The OP has `class ETL` which can be instantiated with `ETL()`, and so `ETL().source(...)` is also valid. Although your recent edit gets closer to the problem. – quamrana Jun 25 '21 at 16:37
  • Yes I agree the function is have return statment – mikegrep Jun 25 '21 at 16:40
  • What do you think the `return` statements should look like? – quamrana Jun 25 '21 at 16:41
  • @quamrana Can you check if this is how it's working or am I on the wrong path here? – christheliz Jun 25 '21 at 17:10
  • I don't think the OP wants to have an `__init__()` method, nor for it to do all the processing. See the duplicate and my answer for where I think the OP is heading. – quamrana Jun 25 '21 at 17:22
1

You've found the answer anyway, but I'll just add some return self to your code:

class ETL:

    def source(self, data_source: str):
        if data_source == 'Simulation':
            simulation()
        elif data_source == 'File':
            main()
        return self

    def sink(self, data_sink: str):
        if data_sink == 'Console':
            command = 'Continue'
            user_command = input('Please type to Continue or to Stop!')
            while command != 'Stop':
                simulation()
        return self

ETL().source('Simulation').sink('Console')

The above code will now work without the error.

However, you also ask about the run() method. I want to know what that is supposed to do. To me it looks like the sink() method, having a while loop is doing the run thing.

Perhaps you meant to do this:

# code elided ...
    def sink(self, data_sink: str):
        self.data_sink = data_sink
        return self

    def run(self):
        if self.data_sink == 'Console':
            command = 'Continue'
            user_command = input('Please type to Continue or to Stop!')
            while command != 'Stop':
                simulation()

# Now this will work:
ETL().source(source_args).sink(sink_args).run()
quamrana
  • 37,849
  • 12
  • 53
  • 71