Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

simplify content and its dependencies #34

Merged
merged 1 commit into from
Jun 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 8 additions & 13 deletions __tests__/apps/flask/README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
# Stock Pricing Service
# Simple Flask application

## About this example
Recreate the `manifest.json` with:

An API allows you to turn your models into production services that other tools and teams can use. APIs are a great way for software engineering teams to use your models without translating them into different languages.


## Learn more

* [Flask Introduction](https://palletsprojects.com/p/flask/)
* [Flask Documentation](https://flask.palletsprojects.com/en/1.1.x/)

## Requirements

* Python 2 versions 2.7 or higher; Python 3 versions 3.5 or higher
```bash
python3.11 -m venv env
. ./env/bin/activate
pip install rsconnect-python
rsconnect write-manifest flask --overwrite .
```
133 changes: 11 additions & 122 deletions __tests__/apps/flask/app.py
Original file line number Diff line number Diff line change
@@ -1,131 +1,20 @@
# -*- coding: utf-8 -*-
import os
import numpy as np
import pandas as pd
from flask import Flask
from flask_restx import Api, Resource, fields
from flask import Flask, jsonify, request, url_for

# Fetch prices from local CSV using pandas
prices = pd.read_csv(
os.path.join(os.path.dirname(__file__), "prices.csv"),
index_col=0,
parse_dates=True,
)


# Configure the Flask app using RestX for swagger documentation
app = Flask(__name__)
app.config["SWAGGER_UI_DOC_EXPANSION"] = "list"
app.config["RESTX_MASK_SWAGGER"] = False
app.config["ERROR_INCLUDE_MESSAGE"] = False


api = Api(
app,
version="0.1.0",
title="Stocks API",
description="The Stocks API provides pricing and volatility data for a "
"limited number of US equities from 2010-2018",
)
ns = api.namespace("stocks")

# Define stock and price models for marshalling and documenting response objects
tickers_model = ns.model(
"Tickers",
{
"tickers": fields.List(
fields.String(description="Ticker of the stock"),
description="All available stock tickers",
),
},
)

stock_model = ns.model(
"Stock",
{
"ticker": fields.String(description="Ticker of the stock"),
"price": fields.Float(description="Latest price of the stock"),
"volatility": fields.Float(description="Latest volatility of the stock price"),
},
)

price_model = ns.model(
"Price",
{
"date": fields.Date,
"high": fields.Float(description="High price for this date"),
"low": fields.Float(description="Low price for this date"),
"close": fields.Float(description="Closing price for this date"),
"volume": fields.Integer(description="Daily volume for this date"),
"adjusted": fields.Float(description="Split-adjusted price for this date"),
},
)


class TickerNotFound(Exception):
def __init__(self, ticker):
self.ticker = ticker
self.message = "Ticker `{}` not found".format(self.ticker)

def __str__(self):
return "TickerNotFound('{}')".format(self.ticker)


# Our simple API only has a few GET endpoints
@ns.route("/")
class StockList(Resource):
"""Shows a list of all available tickers"""

@ns.marshal_with(tickers_model)
def get(self):
tickers = prices["ticker"].unique()
return {"tickers": tickers}


@ns.route("/<string:ticker>")
@ns.response(404, "Ticker not found")
@ns.param("ticker", "The ticker for the stock")
class Stock(Resource):
"""Shows the latest price and volatility for the specified stock"""

@ns.marshal_list_with(stock_model)
def get(self, ticker):
if ticker not in prices["ticker"].unique():
raise TickerNotFound(ticker)

ticker_prices = prices[prices["ticker"] == ticker]
current_price = ticker_prices["close"].last("1d").round(2)
current_volatility = np.log(
ticker_prices["adjusted"] / ticker_prices["adjusted"].shift(1)
).var()

return {
"ticker": ticker,
"price": current_price,
"volatility": current_volatility,
@app.route("/ping")
def ping():
return jsonify(
{
"headers": dict(request.headers),
"environ": dict(os.environ),
"link": url_for("ping"),
"external_link": url_for("ping", _external=True),
}


@ns.route("/<string:ticker>/history")
@ns.response(404, "Ticker not found")
@ns.param("ticker", "The ticker for the stock")
class StockHistory(Resource):
"""Shows the price history for the specified stock"""

@ns.marshal_list_with(price_model)
def get(self, ticker):
if ticker not in prices["ticker"].unique():
raise TickerNotFound(ticker)

ticker_prices = prices[prices["ticker"] == ticker]
ticker_prices["date"] = ticker_prices.index
return ticker_prices.to_dict("records")


@api.errorhandler(TickerNotFound)
def handle_ticker_not_found(error):
return {"message": error.message}, 404
)


if __name__ == "__main__":
app.run(debug=True)
app.run()
20 changes: 7 additions & 13 deletions __tests__/apps/flask/manifest.json
Original file line number Diff line number Diff line change
@@ -1,33 +1,27 @@
{
"version": 1,
"locale": "en_US.UTF-8",
"metadata": {
"appmode": "python-api",
"entrypoint": "app"
},
"locale": "en_US.UTF-8",
"python": {
"version": "3.8.3",
"version": "3.11.8",
"package_manager": {
"name": "pip",
"version": "19.2.3",
"version": "24.0",
"package_file": "requirements.txt"
}
},
"files": {
"requirements.txt": {
"checksum": "8932b9a8a1e488ba6dac3592d8012ced"
"checksum": "cfdea7934019617dc8e2d9a7ea631e00"
},
"README.md": {
"checksum": "5a68ee77af4872bc1b0187a0adb26a5c"
"checksum": "6c47ae2907b4af6076c12704f2e3a375"
},
"app.py": {
"checksum": "9799c3b834b555cf02e5896ad2997674"
},
"prices.csv": {
"checksum": "e0bc27e3dd358c360863807e09079985"
},
"thumbnail.jpg": {
"checksum": "c25a15924781145e8831661e641e5202"
"checksum": "564fcab35569c7ee7b3ddc206fe8cfd0"
}
}
}
}
Loading