earthobservations / wetterdienst

Open weather data for humans.
https://wetterdienst.readthedocs.io/
MIT License
349 stars 54 forks source link

[AttributeError: 'NoneType' object has no attribute 'name'] while calling DWDObservationData #219

Closed sk-drop closed 3 years ago

sk-drop commented 3 years ago

Hey again :) I can't understand the following error I've got and hope you can help me understand it better.

File "/home/skaun/GROLI/wttr/getWeather.py", line 120, in <module>
    cacheData("DAILY")
  File "/home/skaun/GROLI/wttr/getWeather.py", line 106, in cacheData
    obs = DWDObservationData(
  File "/home/skaun/GROLI/env/lib/python3.8/site-packages/wetterdienst/dwd/observations/api.py", line 112, in __init__
    ) = create_parameter_to_parameter_set_combination(
  File "/home/skaun/GROLI/env/lib/python3.8/site-packages/wetterdienst/dwd/observations/util/parameter.py", line 31, in create_parameter_to_parameter_set_combination
    resolution.name
AttributeError: 'NoneType' object has no attribute 'name'

I can tell, that a function within parameter.py doesn't find a 'name' attribute from the resolution I fed her. I expect the culprit is here:

resolution = exec("DWDObservationResolution.{}".format(granularity))

My whole function:

def cacheData(granularity):

    if granularity == "DAILY":
        params = params_daily
    elif granularity == "SUBDAILY":
        params = params_sub
    elif granularity == "HOURLY":
        params = params_hourly

    for param in params:

        parameter = str(param).replace("DWDObservationParameterSet.", "")
        resolution = exec("DWDObservationResolution.{}".format(granularity))

        obs = DWDObservationData(
            station_ids=getSiteIDs(granularity, parameter)[0],
            parameters=[param],
            resolution=resolution,
            start_date="2016-01-01",
            end_date="2020-11-01",
            tidy_data=True,
            humanize_column_names=True)

        for i, df in enumerate(obs.collect_data()):
            name = getSiteIDs("{}".format(granularity), parameter)[1][i]
            makeFile(name, "./data/{}/{}/".format(granularity, parameter), df)
            print('{} ---- {} for {} done'.format(i, parameter, name))

Thank you in advance! :)

sk-drop commented 3 years ago

Got it :) I removed:

resolution = exec("DWDObservationResolution.{}".format(granularity))

and just added:

if granularity == "DAILY":
        params = params_daily
        resolution = DWDObservationResolution.DAILY
    elif granularity == "SUBDAILY":
        params = params_sub
        resolution = DWDObservationResolution.SUBDAILY
    elif granularity == "HOURLY":
        params = params_hourly
        resolution = DWDObservationResolution.HOURLY
amotl commented 3 years ago

Dear Sasha,

thanks for writing in. Please bear with me if I am getting you wrong. From what you are trying to explain here, I figure that you want to use strings like DAILY or HOURLY to select the respective resolution?

You might want to just try feeding this string 1:1 to DWDObservationData's resolution parameter. The command line interface actually does the same thing, see [1]. The parse_enumeration_from_template function should take care of translating the string back to the appropriate Enum item, see [2]. On that matter, you will be able to get rid of any exec()-wizardry altogether, right?

We want Wetterdienst to do what I mean on many levels. Please let us know when it doesn't do that yet by following up on this issue. Your feedback really makes a difference to us.

With kind regards, Andreas.

[1] https://github.com/earthobservations/wetterdienst/blob/v0.10.0/wetterdienst/cli.py#L242-L251 [2] https://github.com/earthobservations/wetterdienst/blob/v0.10.0/wetterdienst/dwd/observations/api.py#L101-L103

gutzbenj commented 3 years ago

Nothing to add from my side. The enum-based definition via DWDObservationResolution, DWDObservationParameter,... can only be used within the library but not the cli.

meteoDaniel commented 3 years ago

@sk-drop an alternative to your code is to use a feature of Enums in python. You can directly pass your string to the Enum:

def cacheData(granularity):

    resolution = DWDObservationResolution(granularity)
    for param in params:

        parameter = str(param).replace("DWDObservationParameterSet.", "")
        obs = DWDObservationData(
            station_ids=getSiteIDs(granularity, parameter)[0],
            parameters=[param],
            resolution=resolution,
            start_date="2016-01-01",
            end_date="2020-11-01",
            tidy_data=True,
            humanize_column_names=True)

        for i, df in enumerate(obs.collect_data()):
            name = getSiteIDs("{}".format(granularity), parameter)[1][i]
            makeFile(name, "./data/{}/{}/".format(granularity, parameter), df)
            print('{} ---- {} for {} done'.format(i, parameter, name))
amotl commented 3 years ago

Oh, now I am seeing that you might want to convert from a string to an Enum item and vice versa.

Let me just quickly share this snippet with you - based on the most recent Wetterdienst 0.10.0.

>>> from wetterdienst.dwd.observations.metadata import DWDObservationResolution

>>> DWDObservationResolution("daily")
<DWDObservationResolution.DAILY: 'daily'>

>>> DWDObservationResolution.DAILY.value
'daily'

Does that help?

Please be aware that parse_enumeration offers additional convenience, as it is able to accept parameters in lowercase and uppercase.

>>> from wetterdienst.util.enumeration import parse_enumeration

>>> parse_enumeration(DWDObservationResolution, "daily")
[<DWDObservationResolution.DAILY: 'daily'>]

>>> parse_enumeration(DWDObservationResolution, "DAILY")
[<DWDObservationResolution.DAILY: 'daily'>]

The Enum itself cannot do that.

>>> DWDObservationResolution("DAILY")
ValueError: 'DAILY' is not a valid DWDObservationResolution
sk-drop commented 3 years ago

Hi! First of all, I appreciate you all for your consideration. I'm amazed with the wholesomeness of this community. I may make a small difference in terms of your optimization for convenience, but you make a big difference in my motivation to continue pursuing a career in programming/data science. Thank YOU for making my day :)

I added the parse_enumeration function and it works as it is intended to; and even in lowercase! :))

Thanks again! Wishing you all the best Stay safe :))

gutzbenj commented 3 years ago

Hi! First of all, I appreciate you all for your consideration. I'm amazed with the wholesomeness of this community. I may make a small difference in terms of your optimization for convenience, but you make a big difference in my motivation to continue pursuing a career in programming/data science. Thank YOU for making my day :)

I added the parse_enumeration function and it works as it is intended to; and even in lowercase! :))

Thanks again! Wishing you all the best Stay safe :))

Dear Sasha, Please feed the resolution directly to the DWDObservationData without parsing! It already includes the parsing of the resolution, period etc so no worry to hand it just a string!

E.g.

DWDObservationData(
    ...,
    resolution="daily",
    ...
)