- Added async support and cross-compatibility between Flask and Quart
- Dropped obsolete modules
db
,gfm
andnlp
- Dropped Python 2.7 support
- Dropped Python 3.6 support as it lacks typing annotations; 3.9+ is now required
- Removed deprecated
docflow
module.StateManager
replaces it - Removed deprecated
make_password
andcheck_password
functions - Added
compress_whitespace
to mimic browser compression of whitespace - Removed unused and untested
word_count
function - Added SQLAlchemy 2.0 support and dropped support for annotations and roles on synonyms
- Registries now support property-like access and caching
- Removed SandboxedFlask as it is unused and adds maintenance overhead
- Fix MarkdownColumn behaviour with None value
manage.py
is no longer supported as Flask-Script has been deprecated- Log reporting over SMS has been removed as it is no longer reliable under the Indian DLT template system; Telegram reporting is typically more effective
- Local stack variables in error logs no longer show app config, and don't repeat already logged values
- Dropped deprecated declared_attr_roles and set_roles
- Added
__json__
protocol inRoleMixin
- Removed unicode_http_header
loader
andafter_loader
are deprecated incoaster.views.ModelView
in favour of a unifiedload
methodcoaster.db
is deprecated as Flask-SQLAlchemy 3.0 has changed architecture to recommend metadata isolation between bind keys even within the same app- App config from
FLASK_*
env vars is now preferred over config files, and support for theFLASK_ENV
var for custom environments is deprecated - Coaster now uses
src
folder layout and has project metadata defined inpyproject.toml
as per PEP 660, requiring setuptools>=61 - Added
coaster.app.JSONProvider
that supports the__json__
protocol - Now compatible with Flask 2.3 and 3.0
- UgliPyJS is no longer offered as a Webassets filter as the dependency is unmaintained, and usage is shifting from Webassets to Webpack
for_tsquery
has been removed as PostgreSQL>=12 has native functionsrender_with
no longer offers a shorthand for JSONP responsescoaster.sqlalchemy.ModelBase
now replaces Flask-SQLAlchemy's db.Model with full support for type hinting- New:
coaster.assets.WebpackManifest
provides Webpack assets in Jinja2 - New:
coaster.utils.DataclassFromType
allows a basic type to be annotated
- Renamed
coaster.roles.set_roles
towith_roles
and added support for wrappingdeclared_attr
and column properties - Restructured roles to match current understanding of principals, actors and anchors
- Added SQLAlchemy column annotations
- Reorganised
coaster.utils
andcoaster.sqlalchemy
into sub-packages LabeledEnum
now supports grouped values if declared as a set- New:
coaster.sqlalchemy.StateManager
adds state management to models - Discontinued:
coaster.utils.*
is no longer available directly ascoaster.*
- Discontinued:
coaster.views.load_models
no longer accepts theworkflow
parameter - New:
requestquery
andrequestform
to complementcoaster.views.requestargs
- New:
coaster.auth
module with acurrent_auth
proxy that provides a standardised API for login managers to use - New:
is_collection
util for testing if an item is a collection data type - New:
coaster.views.requires_permission
decorator - New:
coaster.views.classview
provides a new take on organising views into a class - New:
coaster.utils.classmethodproperty
: like a property, but for class methods - New:
coaster.views.endpoint_for
: discover an endpoint given a URL - Changed:
UuidMixin
no longer providesurl_id
- New:
coaster.sqlalchemy.UrlForMixin
now provides anabsolute_url
property - Changed:
coaster.sqlalchemy.UrlForMixin
now recognises that the project may have multiple apps with distinct URLs for the same content - New:
coaster.sqlalchemy.registry
provides two registries for forms and views associated with models - New:
coaster.views.requires_roles
decorator forModelView
, withis_available
test - New:
UrlForMixin
now providesview_for
andclassview_for
- Changed:
TimestampMixin
optionally usestimestamptz
columns. A future release may make this the default - Changed: Markdown parser has moved to
coaster.utils.markdown
and is no longer a hack to be embarrassed by - New: Unicode whitespace strippers,
ulstrip
,urstrip
andustrip
- Added lazy role grant evaluation and declarative role grants
- New:
nary_op
decorator to turn a binary operator into a chained n-ary operator - Added datasets for limited enumeration in role access, as a stopgap until migration to GraphQL
- Removed ShortUUID in favour of the more stable Base58
- MarkdownColumn now supports a custom markdown processor and options
- New: Support for secret key rotation in Flask apps
- Last version to support Python 2.7; Coaster 0.7 will be Py 3.6+ only
- Removed deprecated
coaster.app.configure
coaster.app.init_app
now takes an optional environment, reading from theFLASK_ENV
environment variable and defaulting toDEVELOPMENT
. This reverses the change introduced in version 0.3.2coaster.manage
no longer accepts environment or callsinit_for
. Apps must do this themselvescoaster.manage
now exposes Alembic migrations via Flask-Migrate instead of Flask-Alembic- When using UUID primary keys in
IdMixin
, a UUID is automatically generated the first time theid
column is accessed, without the need to commit to the database - The underlying implementaiton,
auto_init_default
, is also available for use on other models - The
url_id
property is now part ofIdMixin
and supports SQL queries as well. This makes it compatible with the support forurl_name
inload_models
- New:
shortuuid
module exposed via theutils
module, withsuuid
,suuid2uuid
anduuid2suuid
functions buid
reverts to using UUID4 instead of UUID1mc- The deprecated
newid
alias forbuid
has now been removed - New:
UuidMixin
that adds a UUID secondary key and complementsIdMixin
BaseIdNameMixin
now implementsurl_id_name
(previouslyurl_name
) as a hybrid property and has an additionalurl_name_suuid
property.BaseScopedIdNameMixin
has an upgradedurl_id_name
as wellload_models
no longer hardcodes forurl_name
, instead accepting an optionalurlcheck
list parameter- Added Python 3.6 compatibility
- Removed the unused
nullstr
and renamednullunicode
tonullstr
- New:
add_primary_relationship
to define a primary child on parent models - Added
NoIdMixin
that is BaseMixin minus the id column - New:
require_one_of
util for functions that require any one of many parameters
- Removed
add_and_commit
and associated tests failsafe_add
now takes filters optionally, failing silently in case of error- Added Slack error logging and better throttling for Slack and SMS
- New util:
isoweek_datetime
for week-based datetimes in reports - New util:
midnight_to_utc
for midnight in any timezone converted to UTC
- New util:
uuid1mc
generates a UUID1 with a random multicast MAC id - New util:
uuid1mc_from_datetime
generates a UUID1 with a specific timestamp - IdMixin now supports UUID primary keys
- Deprecated
add_and_commit
in favour offailsafe_add
- New utils:
uuid2buid
andbuid2uuid
- Removed
timestamp_columns
(was deprecated in 0.4.3) - Replaced
py-bcrypt
dependency withbcrypt
buid
now uses UUID1 with random multicast MAC addresses instead of UUID4- New util:
unicode_http_header
converts ASCII HTTP header strings to Unicode - Error traceback in
coaster.logging
now includes request context and session cookie - New:
func.utcnow
for reliable UTC timestamps generated in the database - TimestampMixin now uses
func.utcnow
to move datetime generation server-side
Base(Scoped)?(Id)?NameMixin
now disallows blank names by default. Bumped version number since this is a non-breaking incompatible changeJsonDict
now usesJSONB
on PostgreSQL 9.4- New
CoordinatesMixin
adds latitude and longitude columns - Rudimentary NLP methods
LabeledEnum
now haskeys()
andvalues()
methods as well- Move the query class to
IdMixin
andTimestampMixin
as they are used independently of BaseMixin LabeledEnum
now takes an__order__
specification- New
word_count
util returns word count for HTML documents - New
for_tsquery
formats text queries to PostgreSQL to_tsquery parameters - New
get
andupsert
methods inBase(Scoped)NameMixin
render_with
no longer enables JSON handler by default; now gracefully handles*/*
requestsmanage.py
's shell now allows additional context to be made available inlocals()
coaster.db
now provides a custom SQLAlchemy session with additional helper methods, starting with one:add_and_commit
, which rolls back if the commit fails- Removed
one_or_none
in favor of SQLAlchemy's implementation of the same in 1.0.9 - New
is_url_for
decorator in UrlForMixin
- Initial work on Fluentd logging
- New util:
base_domain_matches
compares if two domains have the same base domain utils.make_name
now returns ASCII slugs instead of Unicode slugs- New:
domain_namespace_match
function coaster.gfm.markdown
now supports optional HTML markup- Deprecated
sqlalchemy.timestamp_columns
, introducingmake_timestamp_columns
sorted_timezones
now includes both country name and timezone name- Base query now has a
notempty()
method that is more efficient thanbool(count())
- New util:
deobfuscate_email
deobfuscates common email obfuscation patterns
NameTitle
namedtuple and support inLabeledEnum
for(value, name, title)
- Provide UglifyJS minifier to webassets via the UglipyJS wrapper
BaseScopedNameMixin
'smake_title
now usesshort_title
as source
views.get_next_url
now considers subdomains as non-externalsqlalchemy.BaseMixin
now provides a new query class withone_or_none
- Coaster now requires all dependencies used by submodules. They are no longer optional
- LabeledEnums now have a
get()
method to emulate dictionaries
- Moved utility functions into
coaster.utils
- Bugfix: make
get_email_domain
somewhat more reliable - Switched to using
coaster.db
in tests - New:
MarkdownColumn
composite column for Markdown content - Changed:
JsonDict
column will use PostgreSQL's native JSON type if the server is PostgreSQL >= 9.2 TimestampMixin
now usesdatetime.utcnow
instead offunc.now
because thenow()
function in PostgreSQL returns local time with timezone, not UTC time, and discards the timezone component if the column doesn't store them. This made timestamps local, not in UTC unless the server was also in UTC- Database tests are now run against both SQLite3 and PostgreSQL
- Bugfix:
PermissionMixin
was mutating inherited permissions - Bugfix:
render_with
no longer attempts to render pre-rendered responses utils.make_name
now takes caller-specified counter numberssqlalchemy.BaseNameMixin
andBaseScopedNameMixin.make_name
now take a reserved names list- New:
utils.nullint
,nullstr
andnullunicode
for returningint(v)
,str(v)
andunicode(v)
ifv
isn't false
short_title
method inBaseScopedNameMixin
assets.require
now raisesAssetNotFound
on missing assets- New:
coaster.db.db
is an instance of Flask-SQLAlchemy
- Bugfix: Support single-char usernames
- New feature: Labeled enumerations
- Enhancement:
load_models
allows choice of permissions and takes additional permissions - Rewrote
requestargs
view decorator for efficiency and ease of use - New
render_with
view decorator - New gfm module for GitHub Flavoured Markdown
load_models
now supports "redirect" models- Logging now looks for
MAIL_DEFAULT_SENDER
beforeDEFAULT_MAIL_SENDER
- Compatibility with Flask 0.10 for SandboxedFlask
- Bugfix:
PermissionMixin.permissions()
now checks if parent is not None
- New
sorted_timezones
function
- New module for asset management, with testcases and documentation.
coaster.logging.configure
is nowinit_app
in keeping with convention
- Updated documentation
- New SQLAlchemy column types and helpers
- Use SQL expressions to set
url_id
in scoped id classes
- Don't use
declared_attr
for theid
,created_at
andupdated_at
columns - Rename
newid
tobuid
but retain old name for compatibility - New
requestargs
view wrapper to make working withrequest.args
easier
- New
SandboxedFlask
incoaster.app
that uses Jinja'sSandboxedEnvironment
load_models
now caches data toflask.g
- SQLAlchemy models now use
declared_attr
for all columns to work around a column duplication bug with joined table inheritance in SQLAlchemy < 0.8 - Misc fixes
get_next_url
now takes a default parameter. Passdefault=None
to returnNone
if no suitable next URL can be foundget_next_url
no longer looks in the session by default. Passsession=True
to look in the session. This was added since poppingnext
from session modifies the session, which shouldn't happen in aget
functionload_models
acceptsg.<name>
notation for parameters to indicate that the parameter should be available asg.<name>
. The view function will get called with just<name>
as usual- If the view requires permissions,
load_models
caches available - permissions as
g.permissions
coaster.views.get_next_url
now looks in the session for the next URL
- New
coaster.app.init_app
function moves away from passing configuration status in environment variables
- SQLAlchemy models now have a
permissions
method thatload_models
looks up
- Added logging module
- First version