Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
Jennifer Li authored and Jennifer Li committed Nov 26, 2024
1 parent 7db4e00 commit 427bef4
Show file tree
Hide file tree
Showing 24 changed files with 703 additions and 113 deletions.
38 changes: 38 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Python
__pycache__
*.pyc
*.pyo
*.pyd
.Python
*.py[cod]

# Environment
.env
venv
.venv
env/
ENV/

# IDE
.idea
.vscode
*.swp
*.swo

# Git
.git
.gitignore

# OS
.DS_Store
Thumbs.db

# Testing
.pytest_cache
.coverage
htmlcov/

# Project specific
*.log
local_settings.py
db.sqlite3
29 changes: 29 additions & 0 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: Build and Push Docker Image

on:
push:
branches:
- main

jobs:
build:
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v2

- name: Log in to Docker Hub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}

- name: Build Docker image
run: make build

- name: Push Docker image
run: make push
env:
DOCKER_ID_USER: ${{ secrets.DOCKER_USERNAME }}
IMAGE_NAME: de_demo
167 changes: 167 additions & 0 deletions .github/workflows/Weather_API.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
# api_key = "b38066974d9946f466ce5632a763aed3"

import requests
from datetime import datetime
from statistics import mean


class WeatherAPI:
def __init__(self, api_key):
"""
Initialize WeatherAPI with your API key
Sign up at: https://openweathermap.org/api to get an API key
"""
self.api_key = api_key
self.base_url = "https://api.openweathermap.org/data/2.5"

def get_current_weather(self, city):
"""Get current weather for a city"""
endpoint = f"{self.base_url}/weather"
params = {
"q": city,
"appid": self.api_key,
"units": "metric", # Use metric units (Celsius, meters/sec)
}

try:
response = requests.get(endpoint, params=params)
response.raise_for_status()
data = response.json()

if "main" not in data or "weather" not in data:
raise ValueError(f"Unexpected API response format: {data}")

weather_info = {
"temperature": data["main"]["temp"],
"feels_like": data["main"]["feels_like"],
"humidity": data["main"]["humidity"],
"description": data["weather"][0]["description"],
"wind_speed": data["wind"]["speed"],
"city": data["name"],
"country": data["sys"]["country"],
"sunrise": datetime.fromtimestamp(data["sys"]["sunrise"]).strftime(
"%H:%M"
),
"sunset": datetime.fromtimestamp(data["sys"]["sunset"]).strftime(
"%H:%M"
),
}

return weather_info

except requests.exceptions.RequestException as e:
print(f"API Request Error: {str(e)}")
return None
except ValueError as e:
print(f"Data Processing Error: {str(e)}")
return None
except Exception as e:
print(f"Unexpected Error: {str(e)}")
return None

def get_forecast(self, city, days=5):
"""Get weather forecast for specified number of days"""
endpoint = f"{self.base_url}/forecast"
params = {"q": city, "appid": self.api_key, "units": "metric"}

try:
response = requests.get(endpoint, params=params)
response.raise_for_status()
data = response.json()

if "list" not in data:
raise ValueError(f"Unexpected API response format: {data}")

# Process forecast data by day
daily_forecasts = {}

for item in data["list"]:
date = datetime.fromtimestamp(item["dt"]).strftime("%Y-%m-%d")

if date not in daily_forecasts:
daily_forecasts[date] = {
"temperatures": [],
"descriptions": [],
"wind_speeds": [],
}

daily_forecasts[date]["temperatures"].append(item["main"]["temp"])
daily_forecasts[date]["descriptions"].append(
item["weather"][0]["description"]
)
daily_forecasts[date]["wind_speeds"].append(item["wind"]["speed"])

# Create summary for each day
forecast = []
for date, data in list(daily_forecasts.items())[:days]:
# Get most common weather description for the day
most_common_description = max(
set(data["descriptions"]), key=data["descriptions"].count
)

forecast.append(
{
"date": date,
"avg_temp": round(mean(data["temperatures"]), 1),
"max_temp": round(max(data["temperatures"]), 1),
"min_temp": round(min(data["temperatures"]), 1),
"description": most_common_description,
"avg_wind": round(mean(data["wind_speeds"]), 1),
}
)

return forecast

except requests.exceptions.RequestException as e:
print(f"API Request Error: {str(e)}")
return None
except ValueError as e:
print(f"Data Processing Error: {str(e)}")
return None
except Exception as e:
print(f"Unexpected Error: {str(e)}")
return None


# Example usage
if __name__ == "__main__":
# Configuration
api_key = "b38066974d9946f466ce5632a763aed3" # Replace with your actual API key
city_name = "San Francisco" # Replace with your desired city
forecast_days = 5 # Number of days for forecast

# Initialize weather API
weather = WeatherAPI(api_key)

# Get and display current weather
current = weather.get_current_weather(city_name)
if current is not None:
print("\nCurrent Weather:")
print(f"City: {current['city']}, {current['country']}")
print(f"Temperature: {current['temperature']}°C")
print(f"Feels like: {current['feels_like']}°C")
print(f"Description: {current['description']}")
print(f"Humidity: {current['humidity']}%")
print(f"Wind Speed: {current['wind_speed']} m/s")
print(f"Sunrise: {current['sunrise']}")
print(f"Sunset: {current['sunset']}")
else:
print(
"Failed to get weather data. Please check your API key and internet connection."
)

# Get and display forecast
print(f"\n{forecast_days}-Day Weather Forecast for {city_name}:")
forecast = weather.get_forecast(city_name, forecast_days)
if forecast is not None:
for day in forecast:
print(f"\n{day['date']}:")
print(
f" Temperature: {day['min_temp']}°C to {day['max_temp']}°C (avg: {day['avg_temp']}°C)"
)
print(f" Description: {day['description']}")
print(f" Wind Speed: {day['avg_wind']} m/s")
else:
print(
"Failed to get forecast data. Please check your API key and internet connection."
)
58 changes: 0 additions & 58 deletions .github/workflows/hello.yml

This file was deleted.

4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
__pycache__/
.DS_Store
.DS_Store
*.pyc
.pytest_cache/
21 changes: 21 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Use an official Python runtime as the base image
FROM python:3.9-slim

# Set the working directory in the container
WORKDIR /app

# Copy the requirements file into the container
COPY requirements.txt .

# Install the required packages
RUN pip install --no-cache-dir -r requirements.txt

# Copy the application code into the container
COPY app.py .
COPY templates/ ./templates/

# Expose the port the app runs on
EXPOSE 5000

# Command to run the application using gunicorn
CMD ["gunicorn", "--bind", "0.0.0.0:5000", "app:app"]
36 changes: 27 additions & 9 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,13 +1,31 @@
install:
pip install --upgrade pip && pip install -r requirements.txt
# Makefile
DOCKER_ID_USER ?= jenniferli6
IMAGE_NAME ?= de_demo
VERSION ?= latest

# Default target - runs when you just type 'make'
.PHONY: all
all: clean install test build push

# Docker commands
build:
docker build -t $(DOCKER_ID_USER)/$(IMAGE_NAME):$(VERSION) .

format:
black *.py
push:
docker push $(DOCKER_ID_USER)/$(IMAGE_NAME):$(VERSION)

run:
docker run -p 5001:5000 $(DOCKER_ID_USER)/$(IMAGE_NAME):$(VERSION)

# Development commands
install:
pip install -r requirements.txt

lint:
pylint --disable=R,C --ignore-patterns=test_.*?py *.py
test:
python -m pytest

test:
python -m pytest -cov=main test_main.py
clean:
find . -type d -name "__pycache__" -exec rm -r {} +
find . -type f -name "*.pyc" -delete

all: install format lint test
.PHONY: build push run install test clean
Loading

0 comments on commit 427bef4

Please sign in to comment.