GithubHelp home page GithubHelp logo

avwx-rest / avwx-api Goto Github PK

View Code? Open in Web Editor NEW
70.0 70.0 78.0 2.4 MB

REST API for parsing aviation weather data

Home Page: https://avwx.rest

License: MIT License

Python 27.70% API Blueprint 72.12% Dockerfile 0.18%

avwx-api's People

Contributors

devdupont avatar janc avatar technicallygio avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

avwx-api's Issues

Error parsing midnight date/time

End time of highlighted TEMPO group not correctly returning "dt" field:

CYVO 061738Z 0618/0706 07005KT P6SM -SN OVC060 TEMPO 0618/0620 3SM -SN BKN030 OVC060 FM062000 06008KT 11/2SM -SN OVC012 TEMPO 0620/0624 6SM -SN OVC025 FM070000 03005KT P6SM -SN OVC025 TEMPO 0700/0702 21/2SM -SN OVC015 FM070200 03005KT P6SM -SN OVC025 PROB30 0702/0704 3SM -FZDZ BR RMK NXT FCST BY 070000Z

"end_time": { "repr": "0624", "dt": "Wed, 06 Feb 2019 00:00:00 GMT" }

Confusingly "0624" represents "Thu, 07 Feb 2019 00:00:00 GMT". ie it should wrap around to midnight the next day. "0600" represents "Wed, 06 Feb 2019 00:00:00 GMT".

Also, could consideration be given to returning the "dt" field as an ISO 8601 date for unambiguous compatibility with more clients? I'm pretty sure python has an isoformat method on datetime objects. It's more succinct while retaining readability. Discussion here:

https://stackoverflow.com/questions/10286204/the-right-json-date-format

TAF bug with PROB and multiple time periods

Hello, I think I've found an issue with parsing of this TAF message:

ESSA 261130Z 2612/2712 VRB02KT 9999 SCT005 BKN030 PROB40 2612/2618 4000 BR BKN004 2618/2706 0300 FZFG VV002 2706/2709 3000 2709/2712 BKN008

Expection

I would expect the message to be parsed into 5 forecast objects, with the following time periods:

TAF code start_time end_time
2612/2712 2024-02-26T12:00:00Z 2024-02-27T12:00:00Z
2612/2618 2024-02-26T12:00:00Z 2024-02-26T18:00:00Z
2618/2706 2024-02-26T18:00:00Z 2024-02-27T06:00:00Z
2706/2709 2024-02-27T06:00:00Z 2024-02-27T09:00:00Z
2709/2712 2024-02-27T09:00:00Z 2024-02-27T12:00:00Z

The JSON should look like this:
expected.json

Expected
    "forecast": [
        {
            ...
            "end_time": {
                "dt": "2024-02-27T12:00:00Z",
                "repr": "2712"
            },
            "flight_rules": "MVFR",
            "icing": [],
            "other": [],
            "probability": null,
            "raw": "2612/2712 VRB02KT 9999 SCT005 BKN030",
            "sanitized": "2612/2712 VRB02KT 9999 SCT005 BKN030",
            "start_time": {
                "dt": "2024-02-26T12:00:00Z",
                "repr": "2612"
            },
            ...
        },
        {
            "altimeter": null,
            "clouds": [
                {
                    "altitude": 4,
                    "modifier": null,
                    "repr": "BKN004",
                    "type": "BKN"
                }
            ],
            "end_time": {
                "dt": "2024-02-26T18:00:00Z",
                "repr": "2618"
            },
            "flight_rules": "MVFR",
            "icing": [],
            "other": [],
            "probability": {
                "repr": "40",
                "spoken": "four zero",
                "value": 40
            },
            "raw": "PROB40 2612/2618 4000 BR BKN004",
            "sanitized": "PROB40 2612/2618 4000 BR BKN004",
            "start_time": {
                "dt": "2024-02-26T12:00:00Z",
                "repr": "2612"
            },
            "summary": "Vis 4km, Mist, Broken layer at 400ft",
            "transition_start": null,
            "turbulence": [],
            "type": "FROM",
            "visibility": {
                "repr": "4000",
                "spoken": "four thousand",
                "value": 4000
            },
            "wind_direction": null,
            "wind_gust": null,
            "wind_shear": null,
            "wind_speed": null,
            "wind_variable_direction": [],
            "wx_codes": [
                {
                    "repr": "BR",
                    "value": "Mist"
                }
            ]
        },
        {
            "altimeter": null,
            "clouds": [
                {
                    "altitude": 2,
                    "modifier": null,
                    "repr": "VV002",
                    "type": "VV"
                }
            ],
            "end_time": {
                "dt": "2024-02-27T06:00:00Z",
                "repr": "2706"
            },
            "flight_rules": "LIFR",
            "icing": [],
            "other": [],
            "probability": {
                "repr": "40",
                "spoken": "four zero",
                "value": 40
            },
            "raw": "2618/2706 0300 FZFG VV002",
            "sanitized": "2618/2706 0300 FZFG VV002",
            "start_time": {
                "dt": "2024-02-26T18:00:00Z",
                "repr": "2618"
            },
            "summary": "Vis 0.3km, Freezing Fog, Vertical visibility up to 200ft",
            "transition_start": null,
            "turbulence": [],
            "type": "FROM",
            "visibility": {
                "repr": "0300",
                "spoken": "three hundred",
                "value": 300
            },
            "wind_direction": null,
            "wind_gust": null,
            "wind_shear": null,
            "wind_speed": null,
            "wind_variable_direction": [],
            "wx_codes": [
                {
                    "repr": "FZFG",
                    "value": "Freezing Fog"
                }
            ]
        },
        {
            "altimeter": null,
            "clouds": [],
            "end_time": {
                "dt": "2024-02-27T09:00:00Z",
                "repr": "2709"
            },
            "flight_rules": "MVFR",
            "icing": [],
            "other": [],
            "probability": {
                "repr": "40",
                "spoken": "four zero",
                "value": 40
            },
            "raw": "2706/2709 3000",
            "sanitized": "2706/2709 3000",
            "start_time": {
                "dt": "2024-02-27T06:00:00Z",
                "repr": "2612"
            },
            "summary": "Vis 3km",
            "transition_start": null,
            "turbulence": [],
            "type": "FROM",
            "visibility": {
                "repr": "3000",
                "spoken": "three thousand",
                "value": 3000
            },
            "wind_direction": null,
            "wind_gust": null,
            "wind_shear": null,
            "wind_speed": null,
            "wind_variable_direction": [],
            "wx_codes": []
        },
        {
            "altimeter": null,
            "clouds": [
                {
                    "altitude": 8,
                    "modifier": null,
                    "repr": "BKN008",
                    "type": "BKN"
                }
            ],
            "end_time": {
                "dt": "2024-02-27T12:00:00Z",
                "repr": "2712"
            },
            "flight_rules": "MVFR",
            "icing": [],
            "other": [],
            "probability": {
                "repr": "40",
                "spoken": "four zero",
                "value": 40
            },
            "raw": "2709/2712 BKN008",
            "sanitized": "2709/2712 BKN008",
            "start_time": {
                "dt": "2024-02-27T09:00:00Z",
                "repr": "2709"
            },
            "summary": "Broken layer at 800ft",
            "transition_start": null,
            "turbulence": [],
            "type": "FROM",
            "visibility": null,
            "wind_direction": null,
            "wind_gust": null,
            "wind_shear": null,
            "wind_speed": null,
            "wind_variable_direction": [],
            "wx_codes": []
        }
    ],

Actual

The message was parsed to only two forecast objects, one for 2612/2712 VRB02KT 9999 SCT005 BKN030 and one for PROB40 2612/2618 4000 BR BKN004 2618/2706 0300 FZFG VV002 2706/2709 3000 2709/2712 BKN008.
As is, there is no way to tell that the VV002 and FZFG codes should apply during 2618/2706.

TAF code start_time end_time
2612/2712 2024-02-26T12:00:00Z 2024-02-27T12:00:00Z
2612/2618 2024-02-26T12:00:00Z 2024-02-26T18:00:00Z

actual.json

Actual
    "forecast": [
        {
            ...
            "end_time": {
                "dt": "2024-02-27T12:00:00Z",
                "repr": "2712"
            },
            "flight_rules": "MVFR",
            "icing": [],
            "other": [],
            "probability": null,
            "raw": "2612/2712 VRB02KT 9999 SCT005 BKN030",
            "sanitized": "2612/2712 VRB02KT 9999 SCT005 BKN030",
            "start_time": {
                "dt": "2024-02-26T12:00:00Z",
                "repr": "2612"
            },
            ...
        },
        {
            "altimeter": null,
            "clouds": [
                {
                    "altitude": 2,
                    "modifier": null,
                    "repr": "VV002",
                    "type": "VV"
                },
                {
                    "altitude": 4,
                    "modifier": null,
                    "repr": "BKN004",
                    "type": "BKN"
                },
                {
                    "altitude": 8,
                    "modifier": null,
                    "repr": "BKN008",
                    "type": "BKN"
                }
            ],
            "end_time": {
                "dt": "2024-02-26T18:00:00Z",
                "repr": "2618"
            },
            "flight_rules": "LIFR",
            "icing": [],
            "other": [
                "2618/2706",
                "0300",
                "2706/2709",
                "3000",
                "2709/2712"
            ],
            "probability": {
                "repr": "40",
                "spoken": "four zero",
                "value": 40
            },
            "raw": "PROB40 2612/2618 4000 BR BKN004 2618/2706 0300 FZFG VV002 2706/2709 3000 2709/2712 BKN008",
            "sanitized": "PROB40 2612/2618 4000 BR BKN004 2618/2706 0300 FZFG VV002 2706/2709 3000 2709/2712 BKN008",
            "start_time": {
                "dt": "2024-02-26T12:00:00Z",
                "repr": "2612"
            },
            "summary": "Vis 4km, Mist, Freezing Fog, Vertical visibility up to 200ft, Broken layer at 400ft, Broken layer at 800ft",
            "transition_start": null,
            "turbulence": [],
            "type": "FROM",
            "visibility": {
                "repr": "4000",
                "spoken": "four thousand",
                "value": 4000
            },
            "wind_direction": null,
            "wind_gust": null,
            "wind_shear": null,
            "wind_speed": null,
            "wind_variable_direction": [],
            "wx_codes": [
                {
                    "repr": "BR",
                    "value": "Mist"
                },
                {
                    "repr": "FZFG",
                    "value": "Freezing Fog"
                }
            ]
        }
    ]

Reproduction

I don't have access to the API so I'm not sure how to reproduce it myself. I was investigating this data to be used in a project, I believe our integration team pulls this data from the taf endpoint.

502 Errors from the API.

We are getting some fairly frequent (multiple times a day) 502's coming back from the API. They appear like this:

{
    "meta": {
        "timestamp": "2019-08-08T16:06:27.607719Z"
    },
    "error": "Report Lookup Error: Unable to reach data source after 5 attempts"
}

The lookup is against OMAA station (Abu Dhabi Intl). We are using a free account on avwx for these queries.

The self hosted avwx-api returns more than one METAR or TAF at once.

Example:
curl 'http://127.0.0.1:8000/api/metar/KLAX?filter=raw'

{
  "meta": {
    "timestamp": "2023-10-23T08:14:09.900113Z", 
    "stations_updated": "2023-10-01"
  }, 
  "raw": "KLAX 230753Z 17006KT 10SM FEW012 BKN016 BKN028 17/16 A2976 RMK AO2 SLP076 T01720156 402280139 $ KLAX 230653Z 24007KT 10SM SCT012 BKN015 BKN075 18/16 A2977 RMK AO2 SLP079 T01780156 $"
}

Note there are two METARs combined at one single line in the returned result, which is unexpected.

Update cache fails when metar contains a special character

Hi again :)

I noticed an exception when the metar contains the $ sign:

Updating cache : {'data': {'Remarks': 'RMK AO2 SLP247 T00611089 $', 'Runway-Vis-List': [], 'Station': 'KNYL', 'Time': '241057Z', 'Cloud-List': [], 'Wind-Direction': '350', 'Wind-Speed': '03', 'Wind-Gust': '', 'Wind-Variable-Dir': [], 'Altimeter': '3026', 'Visibility': '10', 'Other-List': [], 'Temperature': '06', 'Dewpoint': 'M09', 'Units': {'Wind-Speed': 'kt', 'Visibility': 'sm', 'Altitude': 'ft', 'Temperature': 'C', 'Altimeter': 'inHg'}, 'Flight-Rules': 'VFR', 'Remarks-Info': {'Temp-Decimal': '6.1', 'Dew-Decimal': '-8.9'}, 'Raw-Report': 'KNYL 241057Z AUTO 35003KT 10SM CLR 06/M09 A3026 RMK AO2 SLP247 T00611089 $'}, 'translate': {'Visibility': '10sm (16.1km)', 'Altimeter': '30.26inHg (1025hPa)', 'Clouds': 'Sky clear', 'Other': '', 'Wind': 'N-350 at 03kt', 'Temperature': '06C (43F)', 'Dewpoint': '-09C (16F)', 'Remarks': {'AO2': 'Automated with precipitation sensor', 'SLP247': 'Sea level pressure: 1024.7 hPa', 'T00611089': 'Temperature 6.1°C and dewpoint -8.9°C', '$': 'ASOS requires maintenance'}}, 'summary': 'Winds N-350 at 03kt, Vis 10sm, Temp 06C, Dew -09C, Alt 30.26inHg, Sky clear', 'speech': 'Winds three five zero at 3kt. Visibility one zero miles. Temperature six degrees Celsius. Dew point minus nine degrees Celsius. Altimeter three zero point two six. Sky clear'}
[2018-02-24 12:04:14,995] ERROR in app: Exception on /api/metar/KNYL [GET]
Traceback (most recent call last):
  File "/usr/local/lib/python3.6/site-packages/flask/app.py", line 1612, in full_dispatch_request
    rv = self.dispatch_request()
  File "/usr/local/lib/python3.6/site-packages/flask/app.py", line 1598, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/usr/local/lib/python3.6/site-packages/flask_restful/__init__.py", line 480, in wrapper
    resp = resource(*args, **kwargs)
  File "/usr/local/lib/python3.6/site-packages/flask/views.py", line 84, in view
    return self.dispatch_request(*args, **kwargs)
  File "/usr/local/lib/python3.6/site-packages/flask_restful/__init__.py", line 595, in dispatch_request
    resp = meth(*args, **kwargs)
  File "/Volumes/MySamsung/xworkspace/aviation/AVWX-API/avwx_api/api.py", line 101, in get
    return self.get_report(rtype, station)
  File "/Volumes/MySamsung/xworkspace/aviation/AVWX-API/avwx_api/api.py", line 91, in get_report
    resp = handle_report(rtype, station, options, nofail)
  File "/Volumes/MySamsung/xworkspace/aviation/AVWX-API/avwx_api/handling.py", line 114, in handle_report
    data = CACHE.get(rtype, station) or new_report(rtype, station, report)
  File "/Volumes/MySamsung/xworkspace/aviation/AVWX-API/avwx_api/handling.py", line 78, in new_report
    CACHE.update(rtype, data)
  File "/Volumes/MySamsung/xworkspace/aviation/AVWX-API/avwx_api/cache.py", line 48, in update
    self.tables[rtype].update({'_id': data['data']['Station']}, data, upsert=True)
  File "/usr/local/lib/python3.6/site-packages/pymongo/collection.py", line 2968, in update
    write_concern, collation=collation)
  File "/usr/local/lib/python3.6/site-packages/pymongo/collection.py", line 835, in _update_retryable
    _update, session)
  File "/usr/local/lib/python3.6/site-packages/pymongo/mongo_client.py", line 1099, in _retryable_write
    return self._retry_with_session(retryable, func, s, None)
  File "/usr/local/lib/python3.6/site-packages/pymongo/mongo_client.py", line 1076, in _retry_with_session
    return func(session, sock_info, retryable)
  File "/usr/local/lib/python3.6/site-packages/pymongo/collection.py", line 831, in _update
    retryable_write=retryable_write)
  File "/usr/local/lib/python3.6/site-packages/pymongo/collection.py", line 797, in _update
    _check_write_command_response(result)
  File "/usr/local/lib/python3.6/site-packages/pymongo/helpers.py", line 208, in _check_write_command_response
    _raise_last_write_error(write_errors)
  File "/usr/local/lib/python3.6/site-packages/pymongo/helpers.py", line 190, in _raise_last_write_error
    raise WriteError(error.get("errmsg"), error.get("code"), error)
pymongo.errors.WriteError: The dollar ($) prefixed field '$' in 'translate.Remarks.$' is not valid for storage.

I believe the the data should be encoded before inserting them at
https://github.com/flyinactor91/AVWX-API/blob/bed76e4960d46420d2fdcfe424fa814182c2760c/avwx_api/cache.py#L48

Out-of-date TAF returned for nearest airport

Hi

My interpretation of requesting a TAF for the nearest airport would be that the nearest valid report is returned. However, the API currently returns a TAF from the nearest airport, regardless whether or not it is still valid.

For example, the request https://avwx.rest/api/taf/-31.52,115.94?onfail=nearest resulted in (filtered for end_time, meta and raw):

{
  "end_time": {
    "dt": "2023-12-04T09:00:00Z",
    "repr": "0409"
  },
  "meta": {
    "stations_updated": "2023-10-28",
    "timestamp": "2023-12-04T11:28:55.201236Z"
  },
  "raw": "YGIG 032209Z 0400/0409 20008KT 9999 SCT025 FM040200 22016KT 9999 FEW035 RMK T 22 26 27 23 Q 1016 1016 1016 1016"
}

Note the report end-time of "0409" but the request was made almost 2.5h later (ie. after "0411").
Also note that I've tried the onfail=nearest option, but it didn't make a difference.

An airport with a 24/7 TAF (YPEA) would be available only slightly further away from the requested location.

Trying to run a miminally modified Dockerfile

Hi,

I have a docker file that I got from Dockerfile.sample. It builds but hypercorn outputs this error. When I try with gunicorn, I get the same issue. Did I miss a doc or something?

 [2020-06-08 08:58:10 +0000] [10] [INFO] Starting gunicorn 20.0.4
 [2020-06-08 08:58:10 +0000] [10] [INFO] Listening at: http://0.0.0.0:5000 (10)
 [2020-06-08 08:58:10 +0000] [10] [INFO] Using worker: sync
 [2020-06-08 08:58:10 +0000] [16] [INFO] Booting worker with pid: 16
 [2020-06-08 08:58:11 +0000] [16] [ERROR] Exception in worker process
 Traceback (most recent call last):
   File "/usr/local/lib/python3.8/site-packages/gunicorn/arbiter.py", line 583, in spawn_worker
     worker.init_process()
   File "/usr/local/lib/python3.8/site-packages/gunicorn/workers/base.py", line 119, in init_process
     self.load_wsgi()
   File "/usr/local/lib/python3.8/site-packages/gunicorn/workers/base.py", line 144, in load_wsgi
     self.wsgi = self.app.wsgi()
   File "/usr/local/lib/python3.8/site-packages/gunicorn/app/base.py", line 67, in wsgi
     self.callable = self.load()
   File "/usr/local/lib/python3.8/site-packages/gunicorn/app/wsgiapp.py", line 49, in load
     return self.load_wsgiapp()
   File "/usr/local/lib/python3.8/site-packages/gunicorn/app/wsgiapp.py", line 39, in load_wsgiapp
     return util.import_app(self.app_uri)
   File "/usr/local/lib/python3.8/site-packages/gunicorn/util.py", line 358, in import_app
     mod = importlib.import_module(module)
   File "/usr/local/lib/python3.8/importlib/__init__.py", line 127, in import_module
     return _bootstrap._gcd_import(name[level:], package, level)
   File "<frozen importlib._bootstrap>", line 1014, in _gcd_import
   File "<frozen importlib._bootstrap>", line 991, in _find_and_load
   File "<frozen importlib._bootstrap>", line 975, in _find_and_load_unlocked
   File "<frozen importlib._bootstrap>", line 671, in _load_unlocked
   File "<frozen importlib._bootstrap_external>", line 783, in exec_module
   File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
   File "/home/avwx/avwx_api/__init__.py", line 3, in <module>
     from avwx_api import api, views, status
   File "/home/avwx/avwx_api/api/__init__.py", line 1, in <module>
     from . import current, gfs, station
   File "/home/avwx/avwx_api/api/current.py", line 14, in <module>
     class MetarFetch(Report):
   File "/usr/local/lib/python3.8/site-packages/quart_openapi/pint.py", line 286, in decorator
     self._add_resource(func_or_viewcls, path, methods, *args, **kwargs)
   File "/usr/local/lib/python3.8/site-packages/quart_openapi/pint.py", line 199, in _add_resource
     super().add_url_rule(path, endpoint, view_func, methods,  # pylint: disable=no-member
 TypeError: add_url_rule() got multiple values for argument 'provide_automatic_options'

I tried directly on my machine, installing the requirements with pip -Ruv requirements.txt. I followed the docker file basically and ended up with the same error:

seanodea@aurvandr ~/code/flsb/flsb-flask/avwx-api (master)$ hypercorn avwx_api:app --bind 0.0.0.0:5000 -c python:hypercorn_config.py
Process Process-2:
Process Process-1:
Process Process-3:
Traceback (most recent call last):
Traceback (most recent call last):
  File "/usr/lib/python3.8/multiprocessing/process.py", line 315, in _bootstrap
    self.run()
  File "/usr/lib/python3.8/multiprocessing/process.py", line 108, in run
    self._target(*self._args, **self._kwargs)
  File "/home/seanodea/.local/lib/python3.8/site-packages/hypercorn/asyncio/run.py", line 163, in asyncio_worker
    app = load_application(config.application_path)
  File "/home/seanodea/.local/lib/python3.8/site-packages/hypercorn/utils.py", line 92, in load_application
    module = import_module(import_name)
  File "/usr/lib/python3.8/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1014, in _gcd_import
  File "<frozen importlib._bootstrap>", line 991, in _find_and_load
  File "<frozen importlib._bootstrap>", line 975, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 671, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 783, in exec_module
  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
  File "/home/seanodea/code/fl-statusboard/flsb-flask/avwx-api/avwx_api/__init__.py", line 3, in <module>
    from avwx_api import api, views
  File "/home/seanodea/code/fl-statusboard/flsb-flask/avwx-api/avwx_api/api/__init__.py", line 1, in <module>
    from . import current, gfs, station
  File "/home/seanodea/code/fl-statusboard/flsb-flask/avwx-api/avwx_api/api/current.py", line 14, in <module>
    class MetarFetch(Report):
  File "/home/seanodea/.local/lib/python3.8/site-packages/quart_openapi/pint.py", line 286, in decorator
    self._add_resource(func_or_viewcls, path, methods, *args, **kwargs)
  File "/home/seanodea/.local/lib/python3.8/site-packages/quart_openapi/pint.py", line 199, in _add_resource
    super().add_url_rule(path, endpoint, view_func, methods,  # pylint: disable=no-member
TypeError: add_url_rule() got multiple values for argument 'provide_automatic_options'
  File "/usr/lib/python3.8/multiprocessing/process.py", line 315, in _bootstrap
    self.run()
  File "/usr/lib/python3.8/multiprocessing/process.py", line 108, in run
    self._target(*self._args, **self._kwargs)
  File "/home/seanodea/.local/lib/python3.8/site-packages/hypercorn/asyncio/run.py", line 163, in asyncio_worker
    app = load_application(config.application_path)
  File "/home/seanodea/.local/lib/python3.8/site-packages/hypercorn/utils.py", line 92, in load_application
    module = import_module(import_name)
  File "/usr/lib/python3.8/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1014, in _gcd_import
  File "<frozen importlib._bootstrap>", line 991, in _find_and_load
  File "<frozen importlib._bootstrap>", line 975, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 671, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 783, in exec_module
  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
  File "/home/seanodea/code/fl-statusboard/flsb-flask/avwx-api/avwx_api/__init__.py", line 3, in <module>
    from avwx_api import api, views
  File "/home/seanodea/code/fl-statusboard/flsb-flask/avwx-api/avwx_api/api/__init__.py", line 1, in <module>
    from . import current, gfs, station
  File "/home/seanodea/code/fl-statusboard/flsb-flask/avwx-api/avwx_api/api/current.py", line 14, in <module>
    class MetarFetch(Report):
  File "/home/seanodea/.local/lib/python3.8/site-packages/quart_openapi/pint.py", line 286, in decorator
    self._add_resource(func_or_viewcls, path, methods, *args, **kwargs)
  File "/home/seanodea/.local/lib/python3.8/site-packages/quart_openapi/pint.py", line 199, in _add_resource
    super().add_url_rule(path, endpoint, view_func, methods,  # pylint: disable=no-member
TypeError: add_url_rule() got multiple values for argument 'provide_automatic_options'
Traceback (most recent call last):
  File "/usr/lib/python3.8/multiprocessing/process.py", line 315, in _bootstrap
    self.run()
  File "/usr/lib/python3.8/multiprocessing/process.py", line 108, in run
    self._target(*self._args, **self._kwargs)
  File "/home/seanodea/.local/lib/python3.8/site-packages/hypercorn/asyncio/run.py", line 163, in asyncio_worker
    app = load_application(config.application_path)
  File "/home/seanodea/.local/lib/python3.8/site-packages/hypercorn/utils.py", line 92, in load_application
    module = import_module(import_name)
  File "/usr/lib/python3.8/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1014, in _gcd_import
  File "<frozen importlib._bootstrap>", line 991, in _find_and_load
  File "<frozen importlib._bootstrap>", line 975, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 671, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 783, in exec_module
  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
  File "/home/seanodea/code/fl-statusboard/flsb-flask/avwx-api/avwx_api/__init__.py", line 3, in <module>
    from avwx_api import api, views
  File "/home/seanodea/code/fl-statusboard/flsb-flask/avwx-api/avwx_api/api/__init__.py", line 1, in <module>
    from . import current, gfs, station/home/seanodea
  File "/home/seanodea/code/fl-statusboard/flsb-flask/avwx-api/avwx_api/api/current.py", line 14, in <module>
    class MetarFetch(Report):
  File "/home/seanodea/.local/lib/python3.8/site-packages/quart_openapi/pint.py", line 286, in decorator
    self._add_resource(func_or_viewcls, path, methods, *args, **kwargs)
  File "/home/seanodea/.local/lib/python3.8/site-packages/quart_openapi/pint.py", line 199, in _add_resource
    super().add_url_rule(path, endpoint, view_func, methods,  # pylint: disable=no-member
TypeError: add_url_rule() got multiple values for argument 'provide_automatic_options'
Process Process-4:
Traceback (most recent call last):
  File "/usr/lib/python3.8/multiprocessing/process.py", line 315, in _bootstrap
    self.run()
  File "/usr/lib/python3.8/multiprocessing/process.py", line 108, in run
    self._target(*self._args, **self._kwargs)
  File "/home/seanodea/.local/lib/python3.8/site-packages/hypercorn/asyncio/run.py", line 163, in asyncio_worker
    app = load_application(config.application_path)
  File "/home/seanodea/.local/lib/python3.8/site-packages/hypercorn/utils.py", line 92, in load_application
    module = import_module(import_name)
  File "/usr/lib/python3.8/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1014, in _gcd_import
  File "<frozen importlib._bootstrap>", line 991, in _find_and_load
  File "<frozen importlib._bootstrap>", line 975, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 671, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 783, in exec_module
  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
  File "/home/seanodea/code/fl-statusboard/flsb-flask/avwx-api/avwx_api/__init__.py", line 3, in <module>
    from avwx_api import api, views
  File "/home/seanodea/code/fl-statusboard/flsb-flask/avwx-api/avwx_api/api/__init__.py", line 1, in <module>
    from . import current, gfs, station
  File "/home/seanodea/code/fl-statusboard/flsb-flask/avwx-api/avwx_api/api/current.py", line 14, in <module>
    class MetarFetch(Report):
  File "/home/seanodea/.local/lib/python3.8/site-packages/quart_openapi/pint.py", line 286, in decorator
    self._add_resource(func_or_viewcls, path, methods, *args, **kwargs)
  File "/home/seanodea/.local/lib/python3.8/site-packages/quart_openapi/pint.py", line 199, in _add_resource
    super().add_url_rule(path, endpoint, view_func, methods,  # pylint: disable=no-member
TypeError: add_url_rule() got multiple values for argument 'provide_automatic_options'

TAF - Different time formats

Expectation

start_time.dt and end_time.dt is always formatted in the correct ISO 8601 format

Result

The format differs from location to location.

EBBR

https://avwx.rest/api/taf/EBBR

Raw TAF: EBBR 050501Z 0506/0612 06011KT CAVOK

"start_time": {
  "repr": "0506",
  "dt": "2020-05-05T06:00:00+00:00Z"
}

ELLX

https://avwx.rest/api/taf/ELLX

Raw TAF: ELLX 050500Z 0506/0612 04010KT CAVOK

"start_time": {
  "repr": "0506",
  "dt": "2020-05-05T06:00:00Z"
}

It becomes especially difficult when this time has to be parsed for different weather stations. Tools like Moment.js fail.

Furthermore, the notation for EBBR does not appear to be correct. The letter "Z" should never be added when using "+00:00".

Schermafbeelding 2020-05-05 om 08 20 11

Server is Down!

Looks like you reached your quota on Azure. We would be gladly pay for an api key if you stop using the free Azure server(?).

Thnx1

Error parsing statute mile visibility value

When parsing the example TAF below the highlighted visibility is returned with an incorrect value:

CYBC 051338Z 0514/0602 09018G28KT 1/2SM SN VV005 TEMPO 0514/0515 2SM -SN OVC012 FM051500 05012G22KT 11/2SM -SN VV008 TEMPO 0515/0523 3SM -SN OVC010 BECMG 0518/0520 34010KT FM052300 32008KT P6SM BKN030 TEMPO 0523/0601 5SM -SN BKN020 FM060100 31008KT P6SM SCT030 RMK FCST BASED ON AUTO OBS. NXT FCST BY 052000Z

"visibility": { "repr": "11/2", "value": 5.5, "spoken": "five and one half", "numerator": 11, "denominator": 2, "normalized": "5 1/2" }

The numerator should only ever be the single digit before the slash. The preceding figures are units.

Randomly outdated GeoNames metar

Hi @flyinactor91 👋
I noticed that the api.geonames.org services randomly returns outdated metar when querying by coordinates.

Here are two consecutive calls with the same parameters with different results. The correct one is the 1st one (210920Z)

curl http://api.geonames.org/findNearByWeatherJSON\?lat\=35.237\&lng\=-120.643\&radius\=200\&username\=myusername | jq ".weatherObservation.observation"
"KSBP 210920Z AUTO 00000KT 10SM BKN020 BKN033 09/08 A3007 RMK AO2 T00890078 $"

curl http://api.geonames.org/findNearByWeatherJSON\?lat\=35.237\&lng\=-120.643\&radius\=200\&username\=myusername | jq ".weatherObservation.observation"
"KSBP 161415Z 00000KT 1 3/4SM -RA BR OVC005 11/09 A2998 RMK AO2 RAB12 P0000 T01060094"

This happens quite sporadically.

Have you had issues with that before? I wonder if it would be better to always query the aviationweather.gov service for the actual report and use geonames.org to only to get the station name and discard its returned report here

https://github.com/avwx-rest/AVWX-API/blob/8d21e3e89acb61c98fcd20bae1a650e2b861985b/avwx_api/handle/metar.py#L123

cheers

Server error on coordinates lookup with info flag

When a metar report is looked up with the info option by coordinates in the geonames API but the found station does not exist on the AVWX-Engine, the API returns a HTTP 500

Request with the info option

curl -s  https://avwx.rest/api/metar//32.865,-114.393?options=info | jq
{
  "message": "Internal Server Error"
}

Same request without the info option:

curl -s https://avwx.rest/api/metar//32.865,-114.393 | jq

{
  "Altimeter": "3023",
  "Cloud-List": [],
  "Dewpoint": "M02",
  "Flight-Rules": "VFR",
  "Meta": {
    "Cache-Timestamp": "Fri, 23 Feb 2018 13:59:34 GMT",
    "Timestamp": "Fri, 23 Feb 2018 14:01:09 GMT"
  },
  "Other-List": [],
  "Raw-Report": "KLGF 221855Z AUTO 27009G14KT 250V310 10SM SKC 15/M02 A3023",
  "Remarks": "",
  "Remarks-Info": {},
  "Runway-Vis-List": [],
  "Station": "KLGF",
  "Temperature": "15",
  "Time": "221855Z",
  "Units": {
    "Altimeter": "inHg",
    "Altitude": "ft",
    "Temperature": "C",
    "Visibility": "sm",
    "Wind-Speed": "kt"
  },
  "Visibility": "10",
  "Wind-Direction": "270",
  "Wind-Gust": "14",
  "Wind-Speed": "09",
  "Wind-Variable-Dir": [
    "250",
    "310"
  ]
}

In this case, I would give priority to the metar report and return an empty Info json.

https://github.com/flyinactor91/AVWX-API/blob/bed76e4960d46420d2fdcfe424fa814182c2760c/avwx_api/handling.py#L133-L135

if 'info' in opts:
    try:
        resp['Info'] = avwx.Report(station).station_info
    except Exception as e:
        resp['Info'] = {}
return resp

TAF - Forecast times incorrect

Expectation

According to the raw TAF, the first weather group should end at 2020-05-02 1200Z.

Result

end_time.dt returns 2020-05-02T10:00:00+00:00Z
end_time.repr returns 0210

How to reproduce

curl --location --request GET 'https://avwx.rest/api/taf/EBBR'

bugreport

API returns HTTP 200 for invalid ICAO codes

Hi,
when a client submits a non-existing icao code, the API returns correctly an error message

{
	"Error": "Station Lookup Error: METAR not found for ABCD. There might not be a current report in ADDS",
	"Meta": {
		"Timestamp": "Sun, 18 Feb 2018 20:20:21 GMT"
	}
}

but the HTTP code is 200.

curl -I 'https://avwx.rest/api/metar/ABCD'
HTTP/1.1 200 OK
Content-Length: 176
Content-Type: application/json
Server: gunicorn/19.7.1
Access-Control-Allow-Origin: *
Date: Sun, 18 Feb 2018 20:32:36 GMT

I believe the api.py should handle this and return an appropriate error code to the client. In the if error: case:

https://github.com/flyinactor91/AVWX-API/blob/bed76e4960d46420d2fdcfe424fa814182c2760c/avwx_api/api.py#L82-L92

maybe simply:

if error:
    resp = jsonify({'Error': error})
    resp.status_code = 404
    return resp

?onfail=cache says there's no results, even though I was getting new results recently.

One of my lookups for the OMAA ICAO responded with this error:

https://avwx.rest/api/metar/omaa

"Report Lookup Error: Unable to fetch report from NOAA. You might wish to use '?onfail=cache' to return the most recent report even if it's not up-to-date"

A few minutes prior to the lookup that caused this, I had been getting metar information just fine. I decided to add the ?onfail=cache to the request, since I'd rather get some out of date info instead of no info, and then I got this response:

https://avwx.rest/api/metar/omaa?onfail=cache

"No report or cache was found for the requested station"

Something seems odd because I had been getting responses back previously. Unless the cache got dropped for some reason, or I'm misunderstanding the feature.

station airport info are wrong

hello
thank you for this API but have wrong info
example:
OIIE -> have two runway (11R/29L && 11L/29R) but this api show me the just on runway

TAF and ?onfail=nearest

I was hoping that using ?onfail=nearest would return closest airport that reports TAFs. But I think it just returns the closest airport that reports anything including METARs. Is that expected behavior?

[feature request] MOS forecast

Apologies if this has already been requested, but have y'all given thought to adding MOS forecasts? Being able to get a longer-range prediction than the TAF provides would be pretty useful for what I'm working on!

Authorization Token requirements testing.

Good day,

I noticed as per your blog post that come Nov 1st, there will be a mandatory authorization token required for all requests (even Hobby level).

I've made changes to my clients to allow for this, but it's not clear if its being done correctly. Even when including a phony token I'm still getting 200s from my requests. I am worried that, since I can't test my implementation with the token, that I might have an interruption on Nov 1st.

Is there something that I can do to ensure that my requests are conforming to the new requirements ahead of the switchover?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.