poobrains/example.py

402 lines
11 KiB
Python
Executable File

#!/usr/bin/env python
import math
import random
import json
import requests
import datetime
import flask
import numpy
import poobrains
from flask import redirect
app = poobrains.app
@app.route('/')
def front():
return redirect(News.url())
class TestSubForm(poobrains.form.Fieldset):
oink = poobrains.form.fields.Text(label="OMGWTF")
foo = poobrains.form.fields.Text(label="SUBfoo")
submit = poobrains.form.Button('submit', label="SUBSUBMIT")
@app.expose('/form')
class TestForm(poobrains.form.Form):
foo = poobrains.form.fields.Text()
bar = TestSubForm()
optin = poobrains.form.fields.Checkbox(label="Opt-in", default=False, required=True)
radio = poobrains.form.fields.Radio(type=poobrains.form.types.INT, choices=[(1, 'One'), (5, 'Five'), (23, 'Twentythree'), (42, 'Fortytwo')])
multicheck = poobrains.form.fields.Checkbox(label="Check 'em", type=poobrains.form.types.STRING, choices=[('dubs', 'dubs'), ('trips', 'TRIPS'), ('quads', 'QUADS!1!!!!')], multi=True)
completeme = poobrains.form.fields.Text(label="Lookit me, I can autocomplete without JS!", choices=[('Mr. Foo', 'foo'), ('Mr. Florb', 'florb'), ('Ms. Bar', 'bar')])
ranged = poobrains.form.fields.Range()
trigger = poobrains.form.Button('submit', label='Hit me!')
fail = poobrains.form.Button('submit', label='Fail')
def validate(self, submit):
e = poobrains.errors.CompoundError()
if submit == 'fail':
e.append(poobrains.errors.ValidationError("FAIL!", self['foo']))
if len(e):
raise e
def process(self, submit):
flask.flash('TestForm.process called!')
return self
@app.expose('/news', mode='full')
class News(poobrains.commenting.Commentable):
"""
A *news article*.
Has a nice human-readable title and markdown-enabled text.
Also, here's a random list of things to test markdown in class docstrings:
* Jane Fondas Legwarmers
* Gary Buseys Glass-eye
* Peter Thiels head on a pike
"""
class Meta:
search_fields = ['title', 'name', 'text']
title = poobrains.storage.fields.CharField()
text = poobrains.md.MarkdownField()
@app.expose('/paste', mode='full', title='Copypasta')
class Paste(poobrains.tagging.Taggable):
type = poobrains.storage.fields.CharField()
text = poobrains.storage.fields.TextField()
@app.site.box('menu_main')
def menu_main():
menu = poobrains.rendering.Menu('main')
try:
News.permissions['read'].check(flask.g.user)
menu.append(News.url(), 'News')
except poobrains.auth.AccessDenied:
pass
try:
Paste.permissions['read'].check(flask.g.user)
menu.append(Paste.url(), 'Pastes')
except poobrains.auth.AccessDenied:
pass
for url, caption in poobrains.auth.Page.main_menu_entries():
menu.append(url, caption)
return menu
class NonExposed(poobrains.auth.Administerable):
text = poobrains.storage.fields.TextField()
class NonExposedB(NonExposed):
pass
class AVeryVeryLongNameToTestMenuPositioning(poobrains.auth.Administerable):
florp = poobrains.storage.fields.BooleanField()
#class MultiPK(poobrains.auth.Administerable):
#
# class Meta:
# primary_key = peewee.CompositeKey('pk_a', 'pk_b')
#
# pk_a = poobrains.storage.fields.IntegerField()
# pk_b = poobrains.storage.fields.IntegerField()
#
#
#class NestedHandle(poobrains.auth.Administerable):
#
# class Meta:
# primary_key = peewee.CompositeKey('foreign', 'local')
#
# foreign = poobrains.storage.fields.ForeignKeyField(MultiPK)
# local = poobrains.storage.fields.CharField()
@app.site.listing(NonExposedB, '/custom', mode='full', title='Custom Listing')
def list_nonexposed(listing):
return listing
class NEO_Approaches(poobrains.analysis.EphemeralDataset):
title='NASA Near Earth Orbits'
@classmethod
def load(cls, spkid: int = 2099942): # default spkid for apophis
try:
spkid = int(spkid)
except ValueError:
raise poobrains.errors.ValidationError("Invalid SPK ID; must be an integer.")
response = requests.get('https://api.nasa.gov/neo/rest/v1/neo/%d?api_key=DEMO_KEY' % spkid)
if response.status_code != 200:
raise poobrains.errors.ValidationError("NASA API responded with error code %d." % response.status_code)
data = json.loads(response.text)
ds = cls()
ds.title = "Close approaches of %s" % (data['name_limited'] if 'name_limited' in data else data['name'])
ds.description: "**%s** belongs to orbit class **%s**; %s" % (data['name'], data['orbital_data']['orbit_class']['orbit_class_type'], data['orbital_data']['orbit_class']['orbit_class_description'])
ds.plot_data = {
'kind': 'LinePlot',
'layers': {
'approaches': {
'x': 'time',
'y': 'distance'
}
}
}
ds['time'] = {
'title': 'Time',
'description': 'Time of close approach',
'dtype': 'datetime64',
'color': None,
'observations': {},
}
ds['distance'] = {
'title': 'Distance (km)',
'description': 'Distance of close approach',
'dtype': 'float64',
'color': None,
'observations': {},
}
for index, observation in enumerate(data['close_approach_data']):
observation_time = numpy.datetime64(datetime.datetime.fromtimestamp(observation['epoch_date_close_approach'] / 1000))
observation_distance = numpy.float64(observation['miss_distance']['kilometers'])
ds['time']['observations'][index] = observation_time
ds['distance']['observations'][index] = observation_distance
return ds
class Stock_Weekly(poobrains.analysis.EphemeralDataset):
title = 'Stock (weekly)'
@classmethod
def load(cls, symbol='FB'):
response = requests.get('https://www.alphavantage.co/query?function=TIME_SERIES_WEEKLY&symbol=%s&apikey=%s' % (symbol, app.config['ALPHAVANTAGE_API_KEY']))
if response.status_code != 200:
raise poobrains.errors.ValidationError("AlphaVantage API responded with error code %d." % response.status_code)
data = json.loads(response.text)
dates = [x for x in data['Weekly Time Series'].keys()]
first_date = dates[-1]
last_date = dates[0]
ds = cls()
ds.title = symbol
ds.description = f"Data for stock symbol **{symbol}** from *{first_date}* to *{last_date}*."
ds.plot_data = {
'kind': 'LinePlot',
'layers': {
symbol: {
'x': 'time',
'y': 'price'
}
}
}
ds['time'] = {
'title': 'Time',
'description': f"Data for stock symbol **{symbol}** from *{first_date}* to *{last_date}*.",
'dtype': 'datetime64',
'color': None,
'observations': {}
}
ds['price'] = {
'title': 'Price ($)',
'description': f"Data for stock symbol **{symbol}** from *{first_date}* to *{last_date}*.",
'dtype': 'float64',
'color': None,
'observations': {}
}
for index, (datestring, datapoint) in enumerate(data['Weekly Time Series'].items()):
y, m, d = [int(x) for x in datestring.split('-')]
date = datetime.datetime(y, m, d)
ds['time']['observations'][index] = numpy.datetime64(date)
ds['price']['observations'][index] = numpy.float64(datapoint['4. close'])
#error_lower = y - float(datapoint['3. low'])
#error_upper = y - float(datapoint['2. high'])
return ds
class ConstrainedRandom(poobrains.analysis.EphemeralDataset):
title = 'Constrained random'
@classmethod
def load(cls, magnitude: int = 2, length: int = 16):
magnitude, length = int(magnitude), int(length)
ranges = []
for i in range(0, magnitude):
ranges.append(sorted((random.random(), random.random())))
ds = cls()
ds.title = f"Constrained random ({magnitude}, {length})"
ds.description = f"ConstrainedRandom of magnitude {magnitude} and length {length}."
ds.plot_data = {
'kind': 'LinePlot',
'layers': {
'plot': {
'x': 'x',
'y': 'y'
}
}
}
ds['x'] = {
'title': "X",
'description': "Equidistant steps for X-axis.",
'dtype': 'int64',
'color': None,
'observations': {},
}
ds['y'] = {
'title': "Y",
'description': "Random values for Y-axis.",
'dtype': 'float64',
'color': None,
'observations': {},
}
for index, x in enumerate(range(0, length)):
y = random.random()
for r in ranges:
y = r[0] + (r[1] - r[0]) * y
r = ranges[round((len(ranges) - 1) * random.random())] # select random range
y = r[0] + (r[1] - r[0]) * y
y *= math.sin(2 * math.pi * float(i) / length)
ds['x']['observations'][index] = numpy.int64(x)
ds['y']['observations'][index] = numpy.float64(y)
return ds
class Sine(poobrains.analysis.EphemeralDataset):
title = 'Sine'
@classmethod
def load(cls, length: int=10):
ds = cls()
ds.title = f"Sine ({length})"
ds.description = f"A full sine wave out of {length} points."
ds.plot_data = {
'kind': 'LinePlot',
'layers': {
'plot': {
'x': 'x',
'y': 'y'
}
}
}
inc = (2 * math.pi) / (length - 1)
ds['x'] = {
'title': "X",
'description': f"x for `sin(x)`; spaced at equidistance intervals of {inc}.",
'dtype': 'float64',
'color': None,
'observations': {}
}
ds['y'] = {
'title': "Y",
'description': "Result of `sin(x)`",
'dtype': 'float64',
'color': None,
'observations': {}
}
x = 0
for index in range(0, length):
ds['x']['observations'][index] = numpy.float64(x)
ds['y']['observations'][index] = numpy.float64(math.sin(x))
x += inc
return ds
#class RandomMap(poobrains.analysis.geo.EphemeralGeoData):
#
# @classmethod
# def load(cls):
#
# ds = cls()
#
# data = poobrains.analysis.geo.geojson.MultiPolygon()
#
# for poly_num in range(0, random.randrange(1, 8)):
#
# points = []
#
# for point_num in range(0, random.randrange(3, 7)):
# points.append((random.randrange(-180, 181),random.randrange(-75, 76)))
#
# data.coordinates.append([points])
#
# ds.data = poobrains.analysis.geo.geojson.dumps(data)
#
# return ds
if __name__ == '__main__':
#app.run()
poobrains.app.main()