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

Danibishop/longitude rework #32

Merged
merged 52 commits into from
Feb 6, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
738b144
Scaffold as packagestarting in version 0.3.0
Jan 23, 2019
8845ea5
Scaffold structure including initial unit test structure + coverage c…
Jan 23, 2019
64073a7
Scaffold for carto data source including tests.
Jan 23, 2019
37f443a
Added per-query configuration (+ default). Exception wrapping to hide…
Jan 24, 2019
44bf413
Basic example added to query Carto
Jan 24, 2019
fb53a06
100% coverage for Carto data source. Common configuration for on prem…
Jan 24, 2019
7be594a
Added class to wrap query responses, regardless of the database speci…
Jan 24, 2019
2c74c55
Updated doc
Jan 24, 2019
8fb5849
Transparent cache logic inserted in base data source logic. README no…
Jan 25, 2019
ed0023b
Basic RAM cache implementation. Source code folder structure rework t…
Jan 28, 2019
63ba516
Basic Redis put/get feature. Cache config added. Updated README.
Jan 28, 2019
2458d02
Added flush to caches
Jan 28, 2019
000e826
Picke as default cache serializer.
Jan 28, 2019
3fff406
Cache now stores normalized payloads only
Jan 28, 2019
dcd2f10
Updated tests
Jan 28, 2019
08aa397
Added tests for Redis cache and RAM cache. Improved total coverage up…
Jan 28, 2019
fec1359
Cache configuration wrapped in class instead of dictionary (only for …
Jan 28, 2019
1d9c0fe
Initial scaffold for postgres data source
Jan 29, 2019
20ece33
Requied Python version updated to 3.7. Reference to shared google doc…
Jan 29, 2019
f3a7005
Merge branch 'danibishop/longitude-rework' into danibishop/postgres-i…
Jan 29, 2019
2ecf601
Basic Postgres sample running
Jan 29, 2019
fe2078c
psycopg2 package removed in favour of psycopg2-binary distribution. F…
Jan 29, 2019
a50754f
Write query comprobation removed. Closes #33. Use of cache is now con…
Jan 30, 2019
edff45b
Previews for query response removed.
Jan 30, 2019
07054fc
Configuration logic extracted to simple class. Now it is common for d…
Jan 30, 2019
2dd8546
Cache can be safely disabled temporarily using the DisableCache conte…
Jan 30, 2019
60d4680
Common response class extracted to its own module. Rows data is now s…
Jan 30, 2019
4211956
Imports reordered (isort) and setup.py updated with current structure.
Jan 31, 2019
e449a3c
Updated pytest dependency. Added some pytest plugins.
Jan 31, 2019
26e214f
Fix. Queries were being passed already formatted to the specific sub-…
Jan 31, 2019
5a2b610
Fix. Queries were being passed already formatted to the specific sub-…
Jan 31, 2019
e1d7773
Merge branch 'danibishop/longitude-rework' into danibishop/sqlalchemy…
Jan 31, 2019
86a159b
Added SQLAlchemy and dependencies updated.
Jan 31, 2019
d295ad1
get_config() now returns default and custom configurations merged if …
Jan 31, 2019
8aa0034
Merge branch 'danibishop/longitude-rework' of github.com:GeographicaG…
Feb 1, 2019
415772f
Merge branch 'danibishop/distribution-rework' into danibishop/sqlalch…
Feb 1, 2019
120336e
100% coverage for config and helpers. 86% total coverage.
Feb 1, 2019
6feda08
Sample use of SQL Alchemy using Expression Language
Feb 1, 2019
333e275
Bugfix. Cache object was putting parameters instead of payloads.
Feb 1, 2019
10039b0
SQLAlchemy data source full sample.
Feb 1, 2019
a17482e
Configuration object class created.
Feb 1, 2019
7af7f58
Example for configuration file using a Carto and Postgres data source…
Feb 2, 2019
4a36a9a
Merge branch 'danibishop/longitude-rework' of github.com:GeographicaG…
Feb 2, 2019
746788b
Expiration time added to cache interface
Feb 2, 2019
ba494a3
Expanded explanation about issues when rendering binded parameters to…
Feb 2, 2019
78bc949
Source folder renamed as longitude.
Feb 2, 2019
6566bb2
Build + development environment switched to Poetry
Feb 2, 2019
1c43064
Python requirement lowered to 3.6 or bigger instead of 3.7. Fixed cov…
Feb 4, 2019
74773c5
First try with Jenkins + Poetry
Feb 4, 2019
ca0d967
Updated data source base including some shortcut query methods and da…
Feb 5, 2019
11029de
Updated dependencies
Feb 5, 2019
ad0feb7
Config reworked as in ch31846.
Feb 5, 2019
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
30 changes: 30 additions & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# .coveragerc to control coverage.py
[run]
branch = True
omit = src/core/tests/*, **/__init__.py, src/samples/**

[report]
# Regexes for lines to exclude from consideration
exclude_lines =
# Have to re-enable the standard pragma
pragma: no cover

# Don't complain about missing debug-only code:
def __repr__
if self\.debug

# Don't complain if tests don't hit defensive assertion code:
raise AssertionError
raise NotImplementedError

# Don't complain if non-runnable code isn't run:
if 0:
if __name__ == .__main__.:

ignore_errors = True
fail_under = 85
show_missing = True

[html]
title = Longitude Core Coverage
directory = coverage_html_report
14 changes: 14 additions & 0 deletions .env.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Remote db
CARTO_API_KEY=
CARTO_USER=
CARTO_TABLE=

# Local db
POSTGRES_HOST=localhost
POSTGRES_PORT=5432
POSTGRES_DB=longitude
POSTGRES_USER=longitude
POSTGRES_PASS=longitude

# Cache
REDIS_PASSWORD=longitude
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -114,3 +114,11 @@ dmypy.json
# Pyre type checker
.pyre/

# VScode IDE
.vscode

# PyCharm IDE
.idea

# Coverage report
coverage_html_report
25 changes: 25 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
FROM python:3.6.6-slim

ENV PYTHONUNBUFFERED=1

WORKDIR /usr/src/app
ENV PATH="$PATH:/usr/src/app"


# Install anything missing in the slim image, install dependencies
# Remove anything only needed for building
# This is run as one line so docker caches it as a single layer.

COPY pyproject.toml .

RUN set -x \
&& apt-get update \
&& apt-get install -y --no-install-recommends git gcc curl \
&& curl -sSL https://raw.githubusercontent.com/sdispater/poetry/master/get-poetry.py | python \
&& $HOME/.poetry/bin/poetry install \
&& apt-get remove -y --purge git gcc curl \
&& apt-get autoremove -y \
&& apt-get clean -y \
&& rm -rf /var/lib/apt/lists/*

COPY . .
127 changes: 127 additions & 0 deletions Jenkinsfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
#!/usr/bin/env groovy

// Global Environment variables
FAILURE_EMAIL = "[email protected]"
DESIRED_REPOSITORY = "https://github.com/GeographicaGS/Longitude.git"
PUBLISH_BRANCH = "publish"
REPO_NAME = "longitude"

pipeline{
agent { node {
label 'master'
} }

options {
ansiColor('xterm')
}

stages {
stage('Preparing for build') {
agent { node {
label 'master'
} }
steps {
prepareBuild()
}
}
stage ('Building') {
agent { node {
label 'docker'
} }
steps {
sh "docker build --pull=true -t geographica/${REPO_NAME}:${git_commit} ."
}
}
stage('Linter')
{
agent { node {
label 'docker'
} }
steps {
sh "docker run --rm geographica/${REPO_NAME}:${git_commit} /root/.poetry/bin/poetry run pylint --ignore=samples -E longitude"
}
}
stage('Testing')
{
agent { node {
label 'docker'
} }
steps {
sh "docker run --rm geographica/${REPO_NAME}:${git_commit} /root/.poetry/bin/poetry run pytest --cov=longitude.core longitude/core/tests/"
}
}
stage ('Publish') {
agent { node {
label 'docker'
} }
when { anyOf {
branch "${PUBLISH_BRANCH}"
} }
steps{
// TODO: this must be "publish" but we keep "build" while testing the Jenkins pipeline
sh "docker run --rm geographica/${REPO_NAME}:${git_commit} /root/.poetry/bin/poetry build"
}
}
// TODO: Stage to check that module can be imported
}
post {
always {
deleteDir() /* clean up our workspace */
}
unstable {
notifyStatus(currentBuild.currentResult)
}
failure {
notifyStatus(currentBuild.currentResult)
}
}
}

def prepareBuild() {
script {
checkout scm

sh "git rev-parse --short HEAD > .git/git_commit"
sh "git --no-pager show -s --format='%ae' HEAD > .git/git_committer_email"

workspace = pwd()
branch_name = "${ env.BRANCH_NAME }".replaceAll("/", "_")
git_commit = readFile(".git/git_commit").replaceAll("\n", "").replaceAll("\r", "")
//git_commit = sh(returnStdout: true, script: "git describe").trim()
build_name = "${git_commit}"
job_name = "${ env.JOB_NAME }".replaceAll("%2F", "/")
committer_email = readFile(".git/git_committer_email").replaceAll("\n", "").replaceAll("\r", "")
GIT_URL = sh(returnStdout: true, script: "git config --get remote.origin.url").trim()
if ( GIT_URL != DESIRED_REPOSITORY ) {
error("This jenkinsfile is configured for '${ DESIRED_REPOSITORY }' but it was executed from '${ GIT_URL }'.")
}
}
}

def notifyStatus(buildStatus) {
def status
def send_to

try {
switch (branch_name) {
case 'master':
send_to = "${ committer_email }, ${ FAILURE_EMAIL }"
break
default:
send_to = "${ committer_email }"
break
}
} catch(Exception ex) {
send_to = "${ FAILURE_EMAIL }"
}

echo "Sending error email to: ${ send_to }"
try {
mail to: "${ send_to }",
from: "Jenkins Geographica <[email protected]>",
subject: "[${ buildStatus }] ${currentBuild.fullDisplayName}",
body: "Something is wrong in '${currentBuild.fullDisplayName}'. \n\nSee ${env.BUILD_URL} for more details."
} catch(Exception ex) {
echo "Something was wrong sending error email :("
}
}
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2017 Geografía Aplicada S.L

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
121 changes: 121 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# Longitude

A **new** bunch of middleware functions to build applications on top of CARTO.

## Roadmap

- [ ] Database model
- [x] CARTO data source
- [x] Basic parametrized queries (i.e. templated queries)
- [x] Protected parametrized queries (i.e. avoiding injection)
- [ ] Bind/dynamic parameters in queries (server-side render)
- [x] Postgres data source
- [x] psycopg2
- [x] SQLAlchemy
- [x] Cache
- [x] Base cache
- [x] Put
- [x] Get
- [x] Key generation
- [x] Flush
- [x] Tests
- [x] Ram Cache
- [x] Tests
- [x] Redis Cache
- [x] Tests
- [x] Documentation
- [x] Sample scripts
- [x] Unit tests
- [x] Sample scripts

- [x] Config

- [x] CI PyPi versioning

- [ ] Data manipulation
- [ ] Carto
- [ ] DataFrame read/write
- [ ] COPY
- [ ] Postgres
- [ ] DataFrame read/write
- [ ] COPY

- [ ] Validations
- [ ] Marshmallow
- [ ] Wrapper (?)
- [ ] Documentation

- [ ] Swagger
- [ ] Decorators
- [ ] Flassger (?)
- [ ] OAuth integration
- [ ] Postman integration
- [ ] Documentation

- [ ] SQL Alchemy
- [ ] Model definition
- [ ] Jenkins integration
- [ ] Documentation

- [ ] OAuth
- [ ] Role mapping
- [ ] Token storage
- [ ] Documentation

## As final user...

How to use:
```bash
pip install longitude
```

Or:
```bash
pipenv install longitude
```

Or:
```bash
poetry add longitude
```

Or install from GitHub:
```bash
pip install -e git+https://github.com/GeographicaGS/Longitude#egg=longitude
```

## As developer...
danibishop marked this conversation as resolved.
Show resolved Hide resolved

### First time

1. Install ```poetry``` using the [recommended process](https://github.com/sdispater/poetry#installation)
1. poetry is installed globally as a tool
1. It works along with virtualenvironments
1. Create a virtual environment for Python 3.x (check the current development version in ```pyproject.toml```)
1. You can create it wherever you want but do not put it inside the project
1. A nice place is ```$HOME/virtualenvs/longitude```
1. Clone the ```longitude``` repo
1. `cd` to the repo and:
1. Activate the virtual environment: `. ~/virtualenvs/longitude/bin/activate`
1. Run `poetry install`
1. Configure your IDE to use the virtual environment

### Daily

1. Remember to activate the virtual environment

### Why Poetry?

Because it handles development dependencies and packaging with a single file (```pyproject.toml```), which is [already standard](https://flit.readthedocs.io/en/latest/pyproject_toml.html).

## Sample scripts

These are intended to be used with real databases (i.e. those in your profile) to check features of the library. They must be run from the virtual environment.

## Testing and coverage

The [```pytest-cov```](https://pytest-cov.readthedocs.io/en/latest/) plugin is being used. Coverage configuration is at ```.coveragerc``` (including output folder).

You can run something like: ```pytest --cov-report=html --cov=core core``` and the results will go in the defined html folder.

There is a bash script called ```generate_core_coverage.sh``` that runs the coverage analysis and shows the report in your browser.
28 changes: 28 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
version: "3"
services:
python:
image: python:3.6.3-onbuild
command: bash
volumes:
- .:/usr/longitude/app

cache:
image: redis:alpine
ports:
- "6379:6379"
command:
- redis-server
- --requirepass longitude
- --maxmemory 256mb
- --maxmemory-policy allkeys-lru
restart: unless-stopped

postgres:
image: kartoza/postgis
ports:
- "5432:5432"
environment:
POSTGRES_USER: longitude
POSTGRES_PASS: longitude
volumes:
- ./data/:/var/lib/postgresql/data/pgdata
3 changes: 3 additions & 0 deletions generate_core_coverage.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/usr/bin/env bash
pytest --cov-report=html --cov=longitude.core longitude/core/tests/
sensible-browser coverage_html_report/index.html
1 change: 1 addition & 0 deletions longitude/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .core import *
Empty file added longitude/core/__init__.py
Empty file.
Empty file.
Loading