Skip to content

Commit

Permalink
Release 2.8.0 (#230)
Browse files Browse the repository at this point in the history
* Small fix preventing docker from building correctly

* 202 discard outdated forecast (#205)

* Small fix preventing docker from building correctly

* Fixes #202

* 199 fix coveralls (#206)

* testing travis-ci build after this mod...

* another test

* now showing coverage on the master branch instead of the develop one

* now it should be OK

* 210 unicode error (#213)

* Fix integration test

* Possible fix, needs testing

* Making Travis-CI work

* Fixes #216

* Fixes #219

* Alpine docker and switch to tox-travis (#222)

* Dockerfiles and build utils for Alpine containers

* Refactored examples/getTemp.py

* More refactoring due to codeclimate warnings

* switch to tox-travis

* add Simone-Zabberoni to contributors

* update of Linux distro for Travis CI builds

* rename

* moved to online Wiki

* Renamed dockerfiles for Alpine images

* improved build script

* Renamed dockerfile for ubuntu

* UK is wrong - GB is right

* Dockerfiles into one single folder; adapted Docker build and publish scripts; moved test script

* fix

* Fix for #224

* 137 Stations API support (#225)

* Introducing requests as new convenience HTTP client

* New deprecation to be executed upon future version 3.0.0

* Updated with some fixes

* New germinal HTTP Client class

* Cleaned

* Refactoring

* More refactoring, and introducing StationsManagaer class

* forgot

* Station entity, parser and tests; adding more stations_manager methods

* fixing broken build on travis-ci

* Refactoring to allow class deprecations

* More tests and namespace

* time properties in different formats

* Refactoring and more tests

* Seems like IDs are returned with capitalized letters in JSON - and also altitudes can be optional

* Proper testing and stations_manager.create_station

* Trying to fix broken Travis-CI build

* Implemented update of stations (PUT)

* IMplemented deletion of stations (DELETE)

* Fix bug on microseconds parsing

* Integration test

* Fix imports

* Fix documentation

* Forgot

* Fix docs

* AggregatedMeasurement and Measurement classes and their unit tests

* Buffer class and tests

* PersistenceBackends and tests

* CI build is broken, trying to use an old Linux image for builds

* method skeletons

* One more method

* Parser for AggregatedMeasurement objects from JSON

* Stations Manager methods related to measurements and buffer handling

* Committing old work (might break tests)

* refactored stations api version out

* docs

* fix issue with timestamps not having microseconds

* this way empty payloads are handled OK

* No prints, baby

* Now working

* Defaulted to 100 the number of measurements that can be retrieved by the Stations API; fixed data blob sent when posting measurements

* otherwise TRavis-CI builds won't start

* Add few methods to query for "clear" conditions; deprecated on v3.0 the ones querying for "sun" conditions (#227)

* remove diff fragments

* Fix error

* Updated city ID database files

* removed usage of deprecated method

* fix broken test

* bump to version 2.8.0

* documentation and usage examples
  • Loading branch information
csparpa authored Dec 23, 2017
1 parent 1169d52 commit 9ee1f88
Show file tree
Hide file tree
Showing 68 changed files with 2,869 additions and 75 deletions.
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
language: python
python:
- "2.7"
- "3.2"
- "3.3"
- "3.4"
- "3.5"
- "3.6"
install:
- pip install coverage==3.7.1 tox==1.9.2 virtualenv==13.1.2
- pip install coverage==3.7.1 tox-travis virtualenv==13.1.2 coveralls
script:
- tox
- coverage run --rcfile=.coveragerc setup.py test -s tests.unit
Expand All @@ -17,4 +16,5 @@ after_success:
notifications:
email:
on_failure: change
dist: trusty
sudo: false
3 changes: 2 additions & 1 deletion CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ Testing

Packaging and Distribution
--------------------------
* [Diapente] (]https://github.com/Diapente)
* [Diapente] (https://github.com/Diapente)
* [Simone-Zabberoni] (https://github.com/Simone-Zabberoni)

Wiki
----
Expand Down
29 changes: 20 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ A Python wrapper around the OpenWeatherMap API

[![PyPI version](https://badge.fury.io/py/pyowm.svg)](https://badge.fury.io/py/pyowm)
[![Build Status](https://travis-ci.org/csparpa/pyowm.png?branch=master)](https://travis-ci.org/csparpa/pyowm)
[![Coverage Status](https://coveralls.io/repos/csparpa/pyowm/badge.png?branch=develop)](https://coveralls.io/r/csparpa/pyowm?branch=develop)
[![Coverage Status](https://coveralls.io/repos/github/csparpa/pyowm/badge.svg?branch=master)](https://coveralls.io/github/csparpa/pyowm?branch=master)
[![Say Thanks!](https://img.shields.io/badge/Say%20Thanks-!-1EAEDB.svg)](https://saythanks.io/to/csparpa)

## What is it?
Expand Down Expand Up @@ -45,6 +45,8 @@ Please notice that the free API subscription plan is subject to requests throttl

### Examples

That's what you can do with PyOWM and a free OWM API Key:

```python
import pyowm

Expand All @@ -53,13 +55,8 @@ owm = pyowm.OWM('your-API-key') # You MUST provide a valid API key
# Have a pro subscription? Then use:
# owm = pyowm.OWM(API_key='your-API-key', subscription_type='pro')

# Will it be sunny tomorrow at this time in Milan (Italy) ?
forecast = owm.daily_forecast("Milan,it")
tomorrow = pyowm.timeutils.tomorrow()
forecast.will_be_sunny_at(tomorrow) # Always True in Italy, right? ;-)

# Search for current weather in London (UK)
observation = owm.weather_at_place('London,uk')
# Search for current weather in London (Great Britain)
observation = owm.weather_at_place('London,GB')
w = observation.get_weather()
print(w) # <Weather - reference time=2013-12-18 09:20,
# status=Clouds>
Expand All @@ -74,7 +71,21 @@ w.get_temperature('celsius') # {'temp_max': 10.5, 'temp': 9.7, 'temp_min': 9.0}
observation_list = owm.weather_around_coords(-22.57, -43.12)
```

PyOWM usage examples are available [here](https://github.com/csparpa/pyowm/blob/master/pyowm/docs/usage-examples.md).
And this is a usage example with a paid OWM API key:

```python
import pyowm

paid_owm = pyowm.OWM(API_key='your-pro-API-key', subscription_type='pro')

# Will it be clear tomorrow at this time in Milan (Italy) ?
forecast = paid_owm.daily_forecast("Milan,IT")
tomorrow = pyowm.timeutils.tomorrow()
forecast.will_be_clear_at(tomorrow) # The sun always shines on Italy, right? ;-)
```

More PyOWM usage examples are available [here](https://github.com/csparpa/pyowm/blob/master/pyowm/docs/usage-examples.md).


## Documentation
Each release has its own [changelog](https://github.com/csparpa/pyowm/wiki/Changelog).
Expand Down
24 changes: 24 additions & 0 deletions dockerfiles/Dockerfile.alpine-dev
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
FROM alpine:3.7
MAINTAINER Claudio Sparpaglione <[email protected]>

# Install apk packages
RUN apk add --update python python3 python-dev python3-dev py-pip
RUN apk add --update wget gcc linux-headers musl-dev ca-certificates zlib && \
apk add --update gobject-introspection py-gobject py-dbus

# Mount latest source code
ADD . /pyowm
WORKDIR /pyowm
COPY tests/get_temperature.py /usr/bin

#
RUN python setup.py install && \
pip install ipython && \
pip3 install ipython && \
pip install -r /pyowm/dev-requirements.txt && \
pip3 install -r /pyowm/dev-requirements.txt

# Deprecated: Install setuptools and setuptools3
#RUN wget https://bootstrap.pypa.io/ez_setup.py -O - | python && \
# wget https://bootstrap.pypa.io/ez_setup.py -O - | python3

10 changes: 10 additions & 0 deletions dockerfiles/Dockerfile.alpine-py2
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
FROM alpine:3.7
MAINTAINER Claudio Sparpaglione <[email protected]>

RUN apk add --update python py-pip
ADD . /pyowm
WORKDIR /pyowm
COPY tests/get_temperature.py /usr/bin
RUN python setup.py install


11 changes: 11 additions & 0 deletions dockerfiles/Dockerfile.alpine-py3
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
FROM alpine:3.7
MAINTAINER Claudio Sparpaglione <[email protected]>

RUN apk add --update python3 py-pip

ADD . /pyowm
WORKDIR /pyowm
COPY tests/get_temperature.py /usr/bin
RUN python setup.py install


5 changes: 4 additions & 1 deletion Dockerfile → dockerfiles/Dockerfile.ubuntu-py2-py3
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,11 @@ RUN wget https://bootstrap.pypa.io/ez_setup.py -O - | python && \
ADD . /pyowm
WORKDIR /pyowm

# Simple test script to check containers are OK
COPY tests/get_temperature.py /usr/bin

# Update pip and install dev requirements
RUN pip install --upgrade setuptools pip && \
RUN pip install setuptools pip && \
pip install -r /pyowm/dev-requirements.txt

CMD tail -f /dev/null
10 changes: 8 additions & 2 deletions pyowm/abstractions/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,21 @@
from functools import wraps


def deprecated(will_be=None, on_version=None):
def deprecated(will_be=None, on_version=None, name=None):
"""
Function decorator that warns about deprecation upon function invocation.
:param will_be: str representing the target action on the deprecated function
:param on_version: tuple representing a SW version
:param name: name of the entity to be deprecated (useful when decorating
__init__ methods so you can specify the deprecated class name)
:return: callable
"""
def outer_function(function):
warning_msg = '"%s" is deprecated.' % function.__name__
if name is None:
_name = function.__name__
else:
_name = name
warning_msg = '"%s" is deprecated.' % _name
if will_be is not None and on_version is not None:
warning_msg += " It will be %s on version %s" % (
will_be,
Expand Down
67 changes: 67 additions & 0 deletions pyowm/commons/http_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import requests
from pyowm.exceptions import api_call_error, unauthorized_error, not_found_error, \
parse_response_error


class HttpClient(object):

def get_json(self, uri, params=None, headers=None):
resp = requests.get(uri, params=params, headers=headers)
HttpClient.check_status_code(resp.status_code, resp.text)
try:
return resp.status_code, resp.json()
except:
raise parse_response_error.ParseResponseError('Impossible to parse'
'API response data')

def post(self, uri, params=None, data=None, headers=None):
resp = requests.post(uri, params=params, json=data, headers=headers)
HttpClient.check_status_code(resp.status_code, resp.text)
# this is a defense against OWM API responses cointaining an empty body!
try:
json_data = resp.json()
except:
json_data = {}
return resp.status_code, json_data

def put(self, uri, params=None, data=None, headers=None):
resp = requests.put(uri, params=params, json=data, headers=headers)
HttpClient.check_status_code(resp.status_code, resp.text)
# this is a defense against OWM API responses cointaining an empty body!
try:
json_data = resp.json()
except:
json_data = {}
return resp.status_code, json_data

def delete(self, uri, params=None, data=None, headers=None):
resp = requests.delete(uri, params=params, json=data, headers=headers)
HttpClient.check_status_code(resp.status_code, resp.text)
# this is a defense against OWM API responses cointaining an empty body!
try:
json_data = resp.json()
except:
json_data = None
return resp.status_code, json_data


@classmethod
def check_status_code(cls, status_code, payload):
if status_code < 400:
return
if status_code == 400:
raise api_call_error.APICallError(payload)
elif status_code == 401:
raise unauthorized_error.UnauthorizedError('Invalid API Key provided')
elif status_code == 404:
raise not_found_error.NotFoundError('Unable to find the resource')
elif status_code == 502:
raise api_call_error.BadGatewayError('Unable to contact the upstream server')
else:
raise api_call_error.APICallError(payload)

@classmethod
def is_success(cls, status_code):
if 200 <= status_code < 300:
return True
return False
3 changes: 2 additions & 1 deletion pyowm/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
Constants for the PyOWM library
"""

PYOWM_VERSION = '2.7.1'
PYOWM_VERSION = '2.8.0'
LATEST_OWM_API_VERSION = '2.5'
STATIONS_API_VERSION = (3, 0, 0)
DEFAULT_API_KEY = 'b1b15e88fa797225412429c1c50c122a'
7 changes: 7 additions & 0 deletions pyowm/docs/object-model.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,13 @@ This class also provides an iterator for easily iterating over the encapsulated
('2013-09-14 17:00:00+0','Clear')
('2013-09-14 20:00:00+0','Clouds')

Sometimes - due to caching on the OWM API side - the weather objects returned inside a _Forecast_ object
may refer to timestamps in the recent past. In order to remove those outdated weather items
from the forecast, you can do:

>>> fcst.actualize()


### The Forecaster class
Instances of this class are returned by weather forecast queries such as:

Expand Down
Loading

0 comments on commit 9ee1f88

Please sign in to comment.