Skip to content

Commit

Permalink
Merge branch 'release/0.1'
Browse files Browse the repository at this point in the history
  • Loading branch information
rlskoeser committed Mar 6, 2019
2 parents 49f8dba + 14e9226 commit f08cd60
Show file tree
Hide file tree
Showing 45 changed files with 4,595 additions and 0 deletions.
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# Sphinx doc build artifacts
_build/

# top level test settings
/testsettings.py

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
Expand Down
37 changes: 37 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
language: python
python:
- '3.5'
- '3.6'
env:
- SOLR_VERSION=6.6.5
- DJANGO=1.11 SOLR_VERSION=6.6.5
- DJANGO=2.0 SOLR_VERSION=6.6.5
- DJANGO=2.1 SOLR_VERSION=6.6.5
before_install:
- pip install --upgrade pip
- pip install --upgrade pytest
- bash ci/config_solr.sh
cache:
pip: true
directories:
- downloads
before_script:
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
- chmod +x ./cc-test-reporter
install:
- if [ ! -z $DJANGO ]; then pip install -q Django==$DJANGO pytest-django; fi
- pip install -e .
- pip install -e '.[test]'
- pip install codecov
- cp ci/testsettings.py testsettings.py
- python -c "import uuid; print('\nSECRET_KEY = \'%s\'' % uuid.uuid4())" >> testsettings.py
script:
- pytest --cov=parasol
after_success:
- codecov
- if [[ "$TRAVIS_PULL_REQUEST" == "false" && "$TRAVIS_PYTHON_VERSION" == "3.6" ]]; then ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT; fi
before_cache:
- rm -rf downloads/solr-${SOLR_VERSION}
notifications:
slack:
secure: VQzciC3upnIlJPtdEo+z3LletLLsYtM2Ci76aK/ADH1wjEakiU3qNrUgqm7Cp06Hrngx4aBep7nvaRCk4nIAdE7ljGrI1HuoWqig85McIn2dEq1jM+p4rJAQNvqF949GVaJMjJUZi0pGNplDORPSh8c9NI0vzENnnM1yBqsdeA5NOV3HqLiPp49QQ8tUrt4Xy1YfmirnQOHJmwHu/vYlZpDggAaV3+MYVbhaMfHGgvC57QwyvxJjwqYYuCEZy6GDXBl/jayO0kvb0u1ZjeQ31u+JMKeg+kdzcfny8lnnJ4KcMJOAsZ/snwc+AkM6foj6oqC+I8hsVd8Dl5ebPjKU7Kmc8zjH+vBFXF3dtZ0QrtWWahe/p4mtNGDsOEGYQqhnG/ozWAgq14FQwhiJyq411gUbYSrjaeFgbevKzmGC40Diyt0h/BKRI5oeRqcSiqm+yspT8qMyH+3bt/mLpivfn2Enhj2mBSql2HYk9MZv245dUbpEKDsPFNsV2zLl8tnhUzICUPPxCBDzyebg/N3R8Zhz6YQzknDywp9gDWdPlUvzA/ZpnemSiwaedfcfFbvVY276aJO9vo57W+iHJ27OuPLCj5YJqBmQfIIa1LdgADIsGGOeuVEq+drzgoiLalR+0A4xUGw4pPM6gwAcj4/wUm2+kKeMT0QNXgG6J8HL7Ok=
21 changes: 21 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
.. _CHANGELOG:

CHANGELOG
=========

0.1
---

Lightweight python library for Solr indexing, searching and schema
management with optional Django integration.

* Minimal Python Solr API client
* Logic for updating and managing Solr schema
* Indexable mixin for Django models
* QuerySet for querying Solr in an object-oriented fashion similar to
Django QuerySet
* Django Solr client with configuration from Django settings
* Django manage command to configure Solr schema
* Django manage command to index subclasses of Indexable
* `pytest` plugin for unit testing against a test Solr instance in Django
* Basic Sphinx documentation
2 changes: 2 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
include LICENSE
include README.rst
116 changes: 116 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
parasolr
==============

.. sphinx-start-marker-do-not-remove
**parasolr** is a lightweight python library for `Apache Solr`_ indexing,
searching and schema management with optional `Django`_ integration.
It includes a Solr client (`parasolr.solr.SolrClient`). When used with
Django, it provides management commands for updating your Solr schema
configuration and indexing content.

.. _Django: https://www.djangoproject.com/
.. _Apache Solr: http://lucene.apache.org/solr/

.. image:: https://travis-ci.org/Princeton-CDH/parasolr.svg?branch=master
:target: https://travis-ci.org/Princeton-CDH/parasolr
:alt: Build status

.. image:: https://codecov.io/gh/Princeton-CDH/parasolr/branch/master/graph/badge.svg
:target: https://codecov.io/gh/Princeton-CDH/parasolr
:alt: Code coverage

.. image:: https://readthedocs.org/projects/parasolr/badge/?version=latest
:target: https://parasolr.readthedocs.io/en/latest/?badge=latest
:alt: Documentation Status

.. image:: https://api.codeclimate.com/v1/badges/558e86a46c76335f6673/maintainability
:target: https://codeclimate.com/github/Princeton-CDH/parasolr/maintainability
:alt: Maintainability

.. image:: https://requires.io/github/Princeton-CDH/parasolr/requirements.svg?branch=master
:target: https://requires.io/github/Princeton-CDH/parasolr/requirements/?branch=master
:alt: Requirements Status

Currently tested against Python 3.5 and 3.6, Solr 6.6.5, and Django 1.11,
2.0, and 2.1, and without Django.


Installation
------------

Install released version from pypi::

pip install parasolr

To install an unreleased version from GitHub::

pip install git+https://github.com/Princeton-CDH/parasolr@develop#egg=parasolr

To use with Django:

* Add `parasolr` to **INSTALLED_APPS**
* Configure **SOLR_CONNECTIONS** in your django settings::

SOLR_CONNECTIONS = {
'default': {
'URL': 'http://localhost:8983/solr/',
'COLLECTION': 'name',
# any configSet in SOLR_ROOT/server/solr/configsets
'CONFIGSET': 'basic_configs' # optional, basic_configs is default
}
}

* Define a `SolrSchema` with fields and field types for your project.
* Run ``solr_schema`` manage command to configure your schema; it will
prompt to create the Solr core if it does not exist.

.. Note::
The `SolrSchema` must be imported somewhere for it to be
found automatically.


Development instructions
------------------------

This git repository uses git flow branching conventions.

Initial setup and installation:

- *Recommmended*: create and activate a Python 3.6 virtualenv::

virtualenv parasolr -p python3.6
source parasolr/bin/activate

- Install the package with its dependencies as well as development
dependencies::

pip install -e .
pip install -e '.[dev]''

Unit testing
------------

Unit tests are written with `pytest`_ but use some Django
test classes for compatibility with Django test suites. Running the tests
requires a minimal settings file for Django-required configurations.

.. _pytest: http:/docs.pytest.org

- Copy sample test settings and add a secret key::

cp ci/testsettings.py.sample testsettings.py
python -c "import uuid; print('\nSECRET_KEY = \'%s\'' % uuid.uuid4())" >> testsettings.py

- To run the test, either use the configured setup.py test command::

python setup.py test

- Or install test requirements in and use pytest directly::

pip install -e '.[test]'
pytest




29 changes: 29 additions & 0 deletions ci/config_solr.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Config variables local to the script
version=${SOLR_VERSION}
file="solr-${version}.tgz"
url="http://mirror.reverse.net/pub/apache/lucene/solr/${version}/${file}"

# Make a downloads dir to cache and change working dir to it
mkdir -p downloads
cd downloads

# Check if the file exists for some reason, shouldn't but out of parsimony
if [ -f $file ];
then
echo "File exists, skipping download..."
else
wget $url
fi
# Untar
tar xzf $file

# Start the solr instance with all default settings
echo "Starting solr and creating core ${SOLR_CORE}..."
bin="solr-${version}/bin/solr"
$bin start
if [ $? -eq 0 ];
then
echo "Solr appears to have started..."
else
exit 1
fi
36 changes: 36 additions & 0 deletions ci/testsettings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@

# minimal django settings required to run tests
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": "test.db",
}
}

INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'parasolr',
)

# Keeping this blank avoids false detections from SECRET_KEY
# repository checkers.
# SECRET_KEY = ''


# Default CI test settings; imported by parasol.solr.test_solr as testsettings
# from top level project folder
SOLR_CONNECTIONS = {
'default': {
# default config for testing pytest plugin
'URL': 'http://localhost:8983/solr/',
'COLLECTION': 'myplugin',
'TEST': {
'URL': 'http://localhost:8983/solr/',
'COLLECTION': 'parasolr_test',
# aggressive commitWithin for test only
'COMMITWITHIN': 750,
'CONFIGSET': 'basic_configs'
}
}
}
4 changes: 4 additions & 0 deletions doc-requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
django>=1.11
sphinx
sphinxcontrib-napoleon
sphinx-autodoc-typehints
9 changes: 9 additions & 0 deletions parasolr/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

default_app_config = 'parasolr.apps.ParasolConfig'

__version_info__ = (0, 1, 0, None)

# Dot-connect all but the last. Last is dash-connected if not None.
__version__ = '.'.join([str(i) for i in __version_info__[:-1]])
if __version_info__[-1] is not None:
__version__ += ('-%s' % (__version_info__[-1],))
5 changes: 5 additions & 0 deletions parasolr/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from django.apps import AppConfig


class ParasolConfig(AppConfig):
name = 'parasolr'
87 changes: 87 additions & 0 deletions parasolr/django.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
"""
Provides optional Django integration to automatically initialize a
:class:`parasolr.solr.SolrClient` with configurations from Django
settings.
Expected configuration format::
SOLR_CONNECTIONS = {
'default': {
'URL': 'http://localhost:8983/solr/',
'COLLECTION': 'mycore'
}
}
Collection can be omitted when connecting to a single-core Solr
instance.
"""

import logging
from typing import Any, Optional

try:
import django
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
except ImportError:
django = None

from parasolr.solr import client
from parasolr import query


logger = logging.getLogger(__name__)


if django:

class SolrClient(client.SolrClient):
""":class:`~parasolr.solr.client.SolrClient` subclass that
automatically pulls configuration from Django settings.
Args:
*args: Positional arguments to be passed to :class:`parasolr.solr.client.SolrClient`.
**kwargs: Keyword arguments to be passed to :class:`parasolr.solr.client.SolrClient`.
"""

def __init__(self, *args: Any, **kwargs: Any) -> None:
solr_opts = getattr(settings, 'SOLR_CONNECTIONS', None)
# no solr connection section at all
if not solr_opts:
raise ImproperlyConfigured('SolrClient requires SOLR_CONNECTIONS in settings')

default_solr = solr_opts.get('default', None)
# no default config
if not default_solr:
raise ImproperlyConfigured('No "default" section in SOLR_CONNECTIONS configuration')

url = default_solr.get('URL', None)
# URL is required
if not url:
raise ImproperlyConfigured('No URL in default SOLR_CONNECTIONS configuration')

collection = default_solr.get('COLLECTION', '')

# use commit within if configured
commit_within = default_solr.get('COMMITWITHIN', None)
# passed-in value takes precedence
if 'commitWithin' not in kwargs and commit_within:
kwargs['commitWithin'] = commit_within

logger.info('Connecting to default Solr %s%s', url, collection)
super().__init__(url, collection, *args, **kwargs)


class SolrQuerySet(query.SolrQuerySet):
""":class:`~parasolr.query.SolrQuerySet` subclass that
will automatically use :class:`~parasolr.django.SolrClient` if
no solr client is passed on.
Args:
Optional :class:`parasolr.solr.client.SolrClient`.
"""

def __init__(self, solr: Optional[SolrClient] = None):
# use passed-in solr client if there is one;
# otherwise, initialize a django solr client
super().__init__(solr or SolrClient())

0 comments on commit f08cd60

Please sign in to comment.