diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..722c0fd --- /dev/null +++ b/.dockerignore @@ -0,0 +1,29 @@ +*$py.class +*.egg +*.egg-info +*.pyc +*.sqlite +*.sublime-project +*.sublime-workspace +*~ +.*.sw? +.coverage +.DS_Store +.mypy_cache/ +.pytest_cache/ +.sw? +.tox/ +build/ +coverage +coverage.xml +Data.fs* +data/ +development*.ini +dist/ +venv/ +htmlcov/ +nosetests.xml +production.ini +pyvenv.cfg +test +tmp/ diff --git a/Dockerfile b/Dockerfile index 422252f..5e72985 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,15 +1,21 @@ -FROM python:3.12.2-alpine3.19 +FROM python:3.12-slim # Set the working directory WORKDIR /app -# Install PostgreSQL development packages required for psycopg -RUN apk add --no-cache postgresql-dev gcc python3-dev musl-dev +# Install PostgreSQL development packages and other dependencies required for psycopg +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + postgresql-server-dev-all \ + gcc \ + python3-dev \ + build-essential \ + linux-headers-amd64 && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* # Copy the current directory contents into the container at /app COPY . /app # Install any needed packages specified in requirements.txt -RUN pip install --no-cache-dir -r requirements.txt - -ENTRYPOINT [ "pserve" ] +RUN python -m pip install --no-cache-dir -r requirements.txt diff --git a/development.ini.example b/development.ini.example index 426f002..6f3a6f5 100644 --- a/development.ini.example +++ b/development.ini.example @@ -21,6 +21,9 @@ pyramid.available_languages = sqlalchemy.url = sqlite:///%(here)s/riskmatrix.sqlite +openai_api_key= +anthropic_api_key= + session.type = file session.data_dir = %(here)s/data/sessions/data session.lock_dir = %(here)s/data/sessions/lock diff --git a/requirements.txt b/requirements.txt index 1deb8ad..3f95cc4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -48,7 +48,12 @@ zope.event==5.0 zope.interface==6.1 zope.schema==7.0.1 zope.sqlalchemy==3.1 -psycopg2-binary==2.9.9 +numpy==1.26.3 +openai==1.12.0 +plotly==5.18.0 +anthropic redis[hiredis]==5.0.3 +uwsgi==2.0.25.1 +psycopg2-binary==2.9.9 -e . \ No newline at end of file diff --git a/src/riskmatrix/__init__.py b/src/riskmatrix/__init__.py index 8bba6e1..a981841 100644 --- a/src/riskmatrix/__init__.py +++ b/src/riskmatrix/__init__.py @@ -2,6 +2,9 @@ from pyramid.config import Configurator from pyramid_beaker import session_factory_from_settings from typing import Any +from email.headerregistry import Address +from pyramid.settings import asbool +from .mail import PostmarkMailer from riskmatrix.flash import MessageQueue from riskmatrix.i18n import LocaleNegotiator @@ -9,6 +12,8 @@ from riskmatrix.route_factories import root_factory from riskmatrix.security import authenticated_user from riskmatrix.security_policy import SessionSecurityPolicy +from openai import OpenAI +from anthropic import Anthropic from typing import TYPE_CHECKING @@ -22,6 +27,19 @@ def includeme(config: Configurator) -> None: settings = config.registry.settings + default_sender = settings.get( + 'email.default_sender', + 'riskmatrix@seantis.ch' + ) + token = settings.get('mail.postmark_token', '') + stream = settings.get('mail.postmark_stream', 'development') + blackhole = asbool(settings.get('mail.postmark_blackhole', False)) + config.registry.registerUtility(PostmarkMailer( + Address(addr_spec=default_sender), + token, + stream, + blackhole=blackhole + )) config.include('pyramid_beaker') config.include('pyramid_chameleon') config.include('pyramid_layout') @@ -65,11 +83,35 @@ def main( environment=sentry_environment, integrations=[PyramidIntegration(), SqlalchemyIntegration()], traces_sample_rate=1.0, - profiles_sample_rate=0.25, + profiles_sample_rate=1.0, + enable_tracing=True, + send_default_pii=True ) + print("configured sentry") + print(sentry_dsn) with Configurator(settings=settings, root_factory=root_factory) as config: includeme(config) + if openai_apikey := settings.get('openai_api_key'): + + openai_client = OpenAI( + api_key=openai_apikey + ) + config.add_request_method( + lambda r: openai_client, + 'openai', + reify=True + ) + if anthropic_apikey := settings.get('anthropic_api_key'): + anthropic_client = Anthropic( + api_key=anthropic_apikey + ) + config.add_request_method( + lambda r: anthropic_client, + 'anthropic', + reify=True + ) + app = config.make_wsgi_app() return Fanstatic(app, versioning=True) diff --git a/src/riskmatrix/data_table.py b/src/riskmatrix/data_table.py index 936e0e0..5730d7e 100644 --- a/src/riskmatrix/data_table.py +++ b/src/riskmatrix/data_table.py @@ -119,7 +119,6 @@ def cell(self, data: Any) -> str: params = {} if 'class_name' in self.options: params['class'] = self.options['class_name'] - if callable(self.sort_key): params['data_order'] = self.sort_key(data) return f'
- We need to come up
with a slogan
+ Lean Risk Management
`s get reset. However, we also reset the\n// bottom margin to use `rem` units instead of `em`.\n\np {\n margin-top: 0;\n margin-bottom: $paragraph-margin-bottom;\n}\n\n\n// Abbreviations\n//\n// 1. Duplicate behavior to the data-bs-* attribute for our tooltip plugin\n// 2. Add the correct text decoration in Chrome, Edge, Opera, and Safari.\n// 3. Add explicit cursor to indicate changed behavior.\n// 4. Prevent the text-decoration to be skipped.\n\nabbr[title],\nabbr[data-bs-original-title] { // 1\n text-decoration: underline; // 2\n text-decoration: underline dotted; // 2\n cursor: help; // 3\n text-decoration-skip-ink: none; // 4\n}\n\n\n// Address\n\naddress {\n margin-bottom: 1rem;\n font-style: normal;\n line-height: inherit;\n}\n\n\n// Lists\n\nol,\nul {\n padding-left: 2rem;\n}\n\nol,\nul,\ndl {\n margin-top: 0;\n margin-bottom: 1rem;\n}\n\nol ol,\nul ul,\nol ul,\nul ol {\n margin-bottom: 0;\n}\n\ndt {\n font-weight: $dt-font-weight;\n}\n\n// 1. Undo browser default\n\ndd {\n margin-bottom: .5rem;\n margin-left: 0; // 1\n}\n\n\n// Blockquote\n\nblockquote {\n margin: 0 0 1rem;\n}\n\n\n// Strong\n//\n// Add the correct font weight in Chrome, Edge, and Safari\n\nb,\nstrong {\n font-weight: $font-weight-bolder;\n}\n\n\n// Small\n//\n// Add the correct font size in all browsers\n\nsmall {\n @include font-size($small-font-size);\n}\n\n\n// Mark\n\nmark {\n padding: $mark-padding;\n background-color: $mark-bg;\n}\n\n\n// Sub and Sup\n//\n// Prevent `sub` and `sup` elements from affecting the line height in\n// all browsers.\n\nsub,\nsup {\n position: relative;\n @include font-size($sub-sup-font-size);\n line-height: 0;\n vertical-align: baseline;\n}\n\nsub { bottom: -.25em; }\nsup { top: -.5em; }\n\n\n// Links\n\na {\n color: $link-color;\n text-decoration: $link-decoration;\n\n &:hover {\n color: $link-hover-color;\n text-decoration: $link-hover-decoration;\n }\n}\n\n// And undo these styles for placeholder links/named anchors (without href).\n// It would be more straightforward to just use a[href] in previous block, but that\n// causes specificity issues in many other styles that are too complex to fix.\n// See https://github.com/twbs/bootstrap/issues/19402\n\na:not([href]):not([class]) {\n &,\n &:hover {\n color: inherit;\n text-decoration: none;\n }\n}\n\n\n// Code\n\npre,\ncode,\nkbd,\nsamp {\n font-family: $font-family-code;\n @include font-size(1em); // Correct the odd `em` font sizing in all browsers.\n direction: ltr #{\"/* rtl:ignore */\"};\n unicode-bidi: bidi-override;\n}\n\n// 1. Remove browser default top margin\n// 2. Reset browser default of `1em` to use `rem`s\n// 3. Don't allow content to break outside\n\npre {\n display: block;\n margin-top: 0; // 1\n margin-bottom: 1rem; // 2\n overflow: auto; // 3\n @include font-size($code-font-size);\n color: $pre-color;\n\n // Account for some code outputs that place code tags in pre tags\n code {\n @include font-size(inherit);\n color: inherit;\n word-break: normal;\n }\n}\n\ncode {\n @include font-size($code-font-size);\n color: $code-color;\n word-wrap: break-word;\n\n // Streamline the style when inside anchors to avoid broken underline and more\n a > & {\n color: inherit;\n }\n}\n\nkbd {\n padding: $kbd-padding-y $kbd-padding-x;\n @include font-size($kbd-font-size);\n color: $kbd-color;\n background-color: $kbd-bg;\n @include border-radius($border-radius-sm);\n\n kbd {\n padding: 0;\n @include font-size(1em);\n font-weight: $nested-kbd-font-weight;\n }\n}\n\n\n// Figures\n//\n// Apply a consistent margin strategy (matches our type styles).\n\nfigure {\n margin: 0 0 1rem;\n}\n\n\n// Images and content\n\nimg,\nsvg {\n vertical-align: middle;\n}\n\n\n// Tables\n//\n// Prevent double borders\n\ntable {\n caption-side: bottom;\n border-collapse: collapse;\n}\n\ncaption {\n padding-top: $table-cell-padding-y;\n padding-bottom: $table-cell-padding-y;\n color: $table-caption-color;\n text-align: left;\n}\n\n// 1. Removes font-weight bold by inheriting\n// 2. Matches default `