[Python-modules-commits] [django-recurrence] 02/13: Import django-recurrence_1.3.0.orig.tar.gz

Michael Fladischer fladi at moszumanska.debian.org
Tue May 3 18:41:14 UTC 2016


This is an automated email from the git hooks/post-receive script.

fladi pushed a commit to branch master
in repository django-recurrence.

commit 9701c091ddfd818b6a42e2b4dbdb4c3b28497833
Author: Michael Fladischer <FladischerMichael at fladi.at>
Date:   Tue May 3 19:16:23 2016 +0200

    Import django-recurrence_1.3.0.orig.tar.gz
---
 MANIFEST.in                              |   3 +
 PKG-INFO                                 |   4 +-
 README.md                                |  55 ++++++++
 django_recurrence.egg-info/PKG-INFO      |   4 +-
 django_recurrence.egg-info/SOURCES.txt   |  21 ++-
 docs/changelog.rst                       |  32 +++--
 docs/conf.py                             |  10 +-
 docs/github.py                           |  71 +++++++++++
 docs/installation.rst                    |  27 ++--
 docs/usage/getting_started.rst           |  28 ++++
 pytest.ini                               |   3 +
 recurrence/base.py                       |   4 +-
 recurrence/fields.py                     |  34 ++---
 setup.py                                 |   4 +-
 tests/__init__.py                        |   0
 tests/models.py                          |  10 ++
 tests/settings.py                        |  55 ++++++++
 tests/test_exclusions.py                 |  83 ++++++++++++
 tests/test_fields.py                     | 159 +++++++++++++++++++++++
 tests/test_magic_methods.py              |  63 +++++++++
 tests/test_managers_recurrence.py        | 136 ++++++++++++++++++++
 tests/test_managers_rule.py              |  97 ++++++++++++++
 tests/test_nulls.py                      |  27 ++++
 tests/test_occurrences.py                | 211 +++++++++++++++++++++++++++++++
 tests/test_recurrences_without_limits.py | 141 +++++++++++++++++++++
 tests/test_saving.py                     | 183 +++++++++++++++++++++++++++
 tests/test_serialization.py              |  69 ++++++++++
 tests/test_to_text.py                    |  53 ++++++++
 tests/test_to_weekday.py                 |  50 ++++++++
 tests/test_weekday.py                    |  24 ++++
 30 files changed, 1609 insertions(+), 52 deletions(-)

diff --git a/MANIFEST.in b/MANIFEST.in
index 6d4985b..10c1d7a 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,5 +1,8 @@
+include README.md
 include LICENSE
 include MANIFEST.in
+include pytest.ini
 recursive-include docs *
 recursive-include recurrence/static *
 recursive-include recurrence/locale *
+recursive-include tests *
diff --git a/PKG-INFO b/PKG-INFO
index 6827869..b946ee6 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: django-recurrence
-Version: 1.2.0
+Version: 1.3.0
 Summary: Django utility wrapping dateutil.rrule
 Home-page: UNKNOWN
 Author: Tamas Kemenczy
@@ -16,11 +16,11 @@ Classifier: License :: OSI Approved :: BSD License
 Classifier: Operating System :: OS Independent
 Classifier: Programming Language :: Python
 Classifier: Programming Language :: Python :: 2
-Classifier: Programming Language :: Python :: 2.6
 Classifier: Programming Language :: Python :: 2.7
 Classifier: Programming Language :: Python :: 3
 Classifier: Programming Language :: Python :: 3.3
 Classifier: Programming Language :: Python :: 3.4
+Classifier: Programming Language :: Python :: 3.5
 Requires: Django
 Requires: pytz
 Requires: python_dateutil
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..4316194
--- /dev/null
+++ b/README.md
@@ -0,0 +1,55 @@
+# django-recurrence
+
+django-recurrence is a utility for working with recurring dates in
+Django. Documentation is available at
+https://django-recurrence.readthedocs.org/.
+
+It provides:
+
+- Recurrence/Rule objects using a subset of rfc2445 (wraps
+  `dateutil.rrule`) for specifying recurring date/times;
+- `RecurrenceField` for storing recurring datetimes in the database;
+- JavaScript widget.
+
+`RecurrenceField` provides a Django model field which serializes
+recurrence information for storage in the database.
+
+For example - say you were storing information about a university
+course in your app. You could use a model like this:
+
+```python
+import recurrence.fields
+
+class Course(models.Model):
+    title = models.CharField(max_length=200)
+    start = models.TimeField()
+    end = models.TimeField()
+    recurrences = recurrence.fields.RecurrenceField()
+```
+
+You'll notice that I'm storing my own start and end time. The
+recurrence field only deals with _recurrences_ not with specific time
+information. I have an event that starts at 2pm. Its recurrences
+would be "every Friday". For this to work, you'll need to put the
+`recurrence` application into your `INSTALLED_APPS`
+
+## Running the tests
+
+Our test coverage is currently fairly poor (we're working on it!),
+but you can run the tests by making sure you've got the test
+requirements installed:
+
+    pip install -r requirements_test.txt
+
+Once you've done that, you can run the tests using:
+
+    make test
+
+You can generate a coverage report by running:
+
+    make coverage
+
+You can run tests on multiple versions of Python and Django by
+installing tox (`pip install tox`) and running:
+
+    tox
diff --git a/django_recurrence.egg-info/PKG-INFO b/django_recurrence.egg-info/PKG-INFO
index 6827869..b946ee6 100644
--- a/django_recurrence.egg-info/PKG-INFO
+++ b/django_recurrence.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: django-recurrence
-Version: 1.2.0
+Version: 1.3.0
 Summary: Django utility wrapping dateutil.rrule
 Home-page: UNKNOWN
 Author: Tamas Kemenczy
@@ -16,11 +16,11 @@ Classifier: License :: OSI Approved :: BSD License
 Classifier: Operating System :: OS Independent
 Classifier: Programming Language :: Python
 Classifier: Programming Language :: Python :: 2
-Classifier: Programming Language :: Python :: 2.6
 Classifier: Programming Language :: Python :: 2.7
 Classifier: Programming Language :: Python :: 3
 Classifier: Programming Language :: Python :: 3.3
 Classifier: Programming Language :: Python :: 3.4
+Classifier: Programming Language :: Python :: 3.5
 Requires: Django
 Requires: pytz
 Requires: python_dateutil
diff --git a/django_recurrence.egg-info/SOURCES.txt b/django_recurrence.egg-info/SOURCES.txt
index c37aab7..74b02ac 100644
--- a/django_recurrence.egg-info/SOURCES.txt
+++ b/django_recurrence.egg-info/SOURCES.txt
@@ -1,5 +1,7 @@
 LICENSE
 MANIFEST.in
+README.md
+pytest.ini
 setup.py
 django_recurrence.egg-info/PKG-INFO
 django_recurrence.egg-info/SOURCES.txt
@@ -11,6 +13,7 @@ docs/Makefile
 docs/changelog.rst
 docs/conf.py
 docs/contributing.rst
+docs/github.py
 docs/index.rst
 docs/installation.rst
 docs/make.bat
@@ -46,4 +49,20 @@ recurrence/locale/nl/LC_MESSAGES/djangojs.po
 recurrence/static/recurrence/css/recurrence.css
 recurrence/static/recurrence/img/recurrence-calendar-icon.png
 recurrence/static/recurrence/js/recurrence-widget.js
-recurrence/static/recurrence/js/recurrence.js
\ No newline at end of file
+recurrence/static/recurrence/js/recurrence.js
+tests/__init__.py
+tests/models.py
+tests/settings.py
+tests/test_exclusions.py
+tests/test_fields.py
+tests/test_magic_methods.py
+tests/test_managers_recurrence.py
+tests/test_managers_rule.py
+tests/test_nulls.py
+tests/test_occurrences.py
+tests/test_recurrences_without_limits.py
+tests/test_saving.py
+tests/test_serialization.py
+tests/test_to_text.py
+tests/test_to_weekday.py
+tests/test_weekday.py
\ No newline at end of file
diff --git a/docs/changelog.rst b/docs/changelog.rst
index 4ea5a97..c0c7012 100644
--- a/docs/changelog.rst
+++ b/docs/changelog.rst
@@ -1,21 +1,31 @@
 Changelog
 =========
 
-1.2.0 (as yet unreleased)
--------------------------
+1.3.0
+-----
+
+* Drop official support for Django 1.4, Django 1.5, Django 1.6 and
+  Python 2.6 (no changes have been made to deliberately break older
+  versions, but older versions will not be tested going forward);
+* Add official support for Django 1.8 and Django 1.9 (:issue:`62`);
+* Fix for a bug in ``Rule`` creation where the weekday parameter is
+  an instance of ``Weekday`` rather than an integer (:issue:`57`).
+
+1.2.0
+-----
 
 * Added an option for events to occur on the fourth of a given
-  weekday of the month (#29);
+  weekday of the month (:issue:`29`);
 * Fixed an off-by-one bug in the ``to_text`` method for events
-  happening on a regular month each year (#30);
+  happening on a regular month each year (:issue:`30`);
 * Fixed a bug in the JavaScript widget where the date for monthly
   events on a fixed date of the month had the description rendered
   incorrectly if the day selected was more than the number of days in
-  the current calendar month (#31);
-* Added a French translation (#32) - this may be backwards
+  the current calendar month (:issue:`31`);
+* Added a French translation (:issue:`32`) - this may be backwards
   incompatible if have overriden the widget JavaScript such that
   there is no ``language_code`` member of your recurrence object;
-* Added a Spanish translation (#49);
+* Added a Spanish translation (:issue:`49`);
 * Added database migrations - running ``python manage.py migrate
   recurrence --fake`` should be sufficient for this version - nothing
   has changed about the database schema between 1.1.0 and 1.2.0;
@@ -30,11 +40,11 @@ Changelog
 * Removed ``RecurrenceModelField`` and ``RecurrenceModelDescriptor``,
   which don't appear to have worked as expected for some time.
 * Fixed a bug introduced in 1.0.3 which prevented the
-  django-recurrence JavaScript from working (#27).
+  django-recurrence JavaScript from working (:issue:`27`).
 * Don't raise ``ValueError`` if you save ``None`` into a
-  ``RecurrenceField`` with ``null=False`` (#22), for consistency with
-  other field types.
-* Make sure an empty recurrence object is falsey (#25).
+  ``RecurrenceField`` with ``null=False`` (:issue:`22`), for
+  consistency with other field types.
+* Make sure an empty recurrence object is falsey (:issue:`25`).
 * Fix a copy-paste error in ``to_recurrence_object`` which prevented
   exclusion rules from being populated correctly.
 * Fix a typo in ``create_from_recurrence_object`` which prevented it
diff --git a/docs/conf.py b/docs/conf.py
index 97cd742..aa58d91 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -28,7 +28,7 @@ if not on_rtd:
 # If extensions (or modules to document with autodoc) are in another directory,
 # add these directories to sys.path here. If the directory is relative to the
 # documentation root, use os.path.abspath to make it absolute, like shown here.
-#sys.path.insert(0, os.path.abspath('.'))
+sys.path.insert(0, os.path.abspath('.'))
 
 # -- General configuration -----------------------------------------------------
 
@@ -37,7 +37,7 @@ if not on_rtd:
 
 # Add any Sphinx extension module names here, as strings. They can be extensions
 # coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
-extensions = []
+extensions = ['github']
 
 # Add any paths that contain templates here, relative to this directory.
 templates_path = ['_templates']
@@ -60,9 +60,9 @@ copyright = u'2014, django-recurrence developers'
 # built documents.
 #
 # The short X.Y version.
-version = '1.2.0'
+version = '1.3.0'
 # The full version, including alpha/beta/rc tags.
-release = '1.2.0'
+release = '1.3.0'
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
@@ -249,3 +249,5 @@ texinfo_documents = [
 
 # How to display URL addresses: 'footnote', 'no', or 'inline'.
 #texinfo_show_urls = 'footnote'
+
+github_project_url = 'https://github.com/django-recurrence/django-recurrence/'
diff --git a/docs/github.py b/docs/github.py
new file mode 100644
index 0000000..2f7f153
--- /dev/null
+++ b/docs/github.py
@@ -0,0 +1,71 @@
+from docutils import nodes, utils
+from docutils.parsers.rst.roles import set_classes
+
+
+# With thanks to Doug Hellman for writing
+# https://doughellmann.com/blog/2010/05/09/defining-custom-roles-in-sphinx/
+# - this code is derived from an example BitBucket configuration.
+
+
+def make_issue_node(rawtext, app, slug, options):
+    """Create a link to a GitHub issue.
+
+    :param rawtext: Text being replaced with link node.
+    :param app: Sphinx application context
+    :param slug: ID of the thing to link to
+    :param options: Options dictionary passed to role func.
+    """
+    #
+    try:
+        base = app.config.github_project_url
+        if not base:
+            raise AttributeError
+    except AttributeError, err:
+        raise ValueError('github_project_url configuration value is not set (%s)' % str(err))
+
+    slash = '/' if base[-1] != '/' else ''
+    ref = base + slash +  'issues/' + slug + '/'
+    set_classes(options)
+    node = nodes.reference(rawtext, '#' + utils.unescape(slug), refuri=ref,
+                           **options)
+    return node
+
+
+def ghissue_role(name, rawtext, text, lineno, inliner, options={}, content=[]):
+    """Link to a GitHub issue.
+
+    Returns 2 part tuple containing list of nodes to insert into the
+    document and a list of system messages.  Both are allowed to be
+    empty.
+
+    :param name: The role name used in the document.
+    :param rawtext: The entire markup snippet, with role.
+    :param text: The text marked with the role.
+    :param lineno: The line number where rawtext appears in the input.
+    :param inliner: The inliner instance that called us.
+    :param options: Directive options for customization.
+    :param content: The directive content for customization.
+    """
+    try:
+        issue_num = int(text)
+        if issue_num <= 0:
+            raise ValueError
+    except ValueError:
+        msg = inliner.reporter.error(
+            'GitHub issue number must be a number greater than or equal to 1; '
+            '"%s" is invalid.' % text, line=lineno)
+        prb = inliner.problematic(rawtext, rawtext, msg)
+        return [prb], [msg]
+    app = inliner.document.settings.env.app
+    node = make_issue_node(rawtext, app, str(issue_num), options)
+    return [node], []
+
+
+def setup(app):
+    """Install the plugin.
+
+    :param app: Sphinx application context.
+    """
+    app.add_role('issue', ghissue_role)
+    app.add_config_value('github_project_url', None, 'env')
+    return
diff --git a/docs/installation.rst b/docs/installation.rst
index ddffb0c..558db34 100644
--- a/docs/installation.rst
+++ b/docs/installation.rst
@@ -27,28 +27,26 @@ Then, make sure ``recurrence`` is in your ``INSTALLED_APPS`` setting:
 Supported Django and Python versions
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-Currently, django-recurrence supports Python 2.6, Python 2.7, Python
-3.3 and Python 3.4. Python 3 support is experimental (we run our
-tests against Python 3, but have not yet tried it in production).
+Currently, django-recurrence supports Python 2.7, Python 3.3, Python
+3.4 and Python 3.5.
 
-django-recurrence works with Django from versions 1.4 to 1.7 (though
-note that Django 1.4 does not support Python 3, Django 1.7 does not
-support Python 2.6, and Python 3.4 is only supported with Django
-1.7).
+django-recurrence works with Django from versions 1.7 to 1.9.
 
 Set up internationalization
 ---------------------------
 
 .. note::
 
-    If you just want to use the ``en`` translation, you can skip this
-    step.
+    This step is currently mandatory, but may be bypassed with an
+    extra bit of javascript. See [issue
+    #47](https://github.com/django-recurrence/django-recurrence/issues/47)
+    for details.
 
-If you want to use a translation of django-recurrence other than
-``en``, you'll need to ensure django-recurrence's JavaScript can
+Using a translation of django-recurrence other than
+``en`` requires that django-recurrence's JavaScript can
 access the translation strings. This is handled with Django's built
-in ``javascript_catalog`` view, which you install by adding the
-following to your ``urls.py`` file:
+in ``javascript_catalog`` view, which you must install by adding the
+following to your project ``urls.py`` file:
 
 .. code-block:: python
 
@@ -75,3 +73,6 @@ to ensure you also have ``django.contrib.staticfiles`` in your
 ``INSTALLED_APPS`` setting, and run::
 
     python manage.py collectstatic
+
+.. note::
+   After collecting static files, you can use {{ form.media }} to include recurrence's static files within your templates.
diff --git a/docs/usage/getting_started.rst b/docs/usage/getting_started.rst
index ff19200..55011dd 100644
--- a/docs/usage/getting_started.rst
+++ b/docs/usage/getting_started.rst
@@ -25,3 +25,31 @@ Using this form it's possible to specify relatively complex
 recurrence rules - such as an event that happens every third Thursday
 of the month, unless that Thursday happens to be the 21st of the
 month, and so on.
+
+
+Form Usage
+----------------------
+
+.. code-block:: python
+
+   from django import forms
+   from .models import Course
+
+   class CourseForm(forms.ModelForm):
+      class Meta:
+         model = Course
+         fields = ('title', 'recurrences',)
+         
+.. note::
+
+   Be sure to add {{ form.media }} to your template or statically link recurrence.css and recurrence.js. 
+
+.. code-block:: html
+
+   
+   <form method="POST" class="post-form">
+       {% csrf_token %}
+       {{ form.media }}
+       {{ form }}
+       <button type="submit">Submit</button>
+   </form>     
diff --git a/pytest.ini b/pytest.ini
new file mode 100644
index 0000000..66886cb
--- /dev/null
+++ b/pytest.ini
@@ -0,0 +1,3 @@
+[pytest]
+DJANGO_SETTINGS_MODULE = tests.settings
+addopts = --tb=short
diff --git a/recurrence/base.py b/recurrence/base.py
index 94ca639..6a8ba66 100644
--- a/recurrence/base.py
+++ b/recurrence/base.py
@@ -289,7 +289,7 @@ class Recurrence(object):
     """
     def __init__(
         self, dtstart=None, dtend=None,
-        rrules=[], exrules=[], rdates=[], exdates=[]
+        rrules=(), exrules=(), rdates=(), exdates=()
     ):
         """
         Create a new recurrence.
@@ -842,7 +842,7 @@ def serialize(rule_or_recurrence):
         if rule.interval != 1:
             values.append((u'INTERVAL', [str(int(rule.interval))]))
         if rule.wkst:
-            values.append((u'WKST', [Rule.weekdays[rule.wkst]]))
+            values.append((u'WKST', [Rule.weekdays[getattr(rule.wkst, 'number', rule.wkst)]]))
 
         if rule.count is not None:
             values.append((u'COUNT', [str(rule.count)]))
diff --git a/recurrence/fields.py b/recurrence/fields.py
index 7f58ebb..783d52b 100644
--- a/recurrence/fields.py
+++ b/recurrence/fields.py
@@ -1,6 +1,6 @@
 from django.db.models import fields
-from django.db.models.fields.subclassing import SubfieldBase
-from django.utils.six import string_types, with_metaclass
+from django.utils.six import string_types
+from django.db.models.fields.subclassing import Creator
 
 import recurrence
 from recurrence import forms
@@ -14,30 +14,34 @@ except ImportError:
     pass
 
 
-class RecurrenceField(with_metaclass(SubfieldBase, fields.Field)):
-    """
-    Field that stores a `recurrence.base.Recurrence` object to the
-    database.
-    """
+# Do not use SubfieldBase meta class because is removed in Django 1.10
+
+class RecurrenceField(fields.Field):
+    """Field that stores a `recurrence.base.Recurrence` to the database."""
 
     def get_internal_type(self):
         return 'TextField'
 
     def to_python(self, value):
-        if value is None:
-            return value
-        if isinstance(value, recurrence.Recurrence):
+        if value is None or isinstance(value, recurrence.Recurrence):
             return value
         value = super(RecurrenceField, self).to_python(value) or u''
         return recurrence.deserialize(value)
 
-    def get_db_prep_value(self, value, connection=None, prepared=False):
-        if isinstance(value, string_types):
-            value = recurrence.deserialize(value)
-        return recurrence.serialize(value)
+    def from_db_value(self, value, *args, **kwargs):
+        return self.to_python(value)
+
+    def get_prep_value(self, value):
+        if not isinstance(value, string_types):
+            value = recurrence.serialize(value)
+        return value
+
+    def contribute_to_class(self, cls, *args, **kwargs):
+        super(RecurrenceField, self).contribute_to_class(cls, *args, **kwargs)
+        setattr(cls, self.name, Creator(self))
 
     def value_to_string(self, obj):
-        return self.get_db_prep_value(self._get_val_from_obj(obj))
+        return self.get_prep_value(self._get_val_from_obj(obj))
 
     def formfield(self, **kwargs):
         defaults = {
diff --git a/setup.py b/setup.py
index 89afa08..6043929 100644
--- a/setup.py
+++ b/setup.py
@@ -43,7 +43,7 @@ else:
 
 setup(
     name='django-recurrence',
-    version='1.2.0',
+    version='1.3.0',
     license='BSD',
 
     description='Django utility wrapping dateutil.rrule',
@@ -59,11 +59,11 @@ setup(
         'Operating System :: OS Independent',
         'Programming Language :: Python',
         "Programming Language :: Python :: 2",
-        'Programming Language :: Python :: 2.6',
         'Programming Language :: Python :: 2.7',
         "Programming Language :: Python :: 3",
         "Programming Language :: Python :: 3.3",
         "Programming Language :: Python :: 3.4",
+        "Programming Language :: Python :: 3.5",
     ),
 
     requires=(
diff --git a/tests/__init__.py b/tests/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/models.py b/tests/models.py
new file mode 100644
index 0000000..7bc99b2
--- /dev/null
+++ b/tests/models.py
@@ -0,0 +1,10 @@
+from django.db import models
+from recurrence.fields import RecurrenceField
+
+
+class EventWithNoNulls(models.Model):
+    recurs = RecurrenceField(null=False)
+
+
+class EventWithNulls(models.Model):
+    recurs = RecurrenceField(null=True)
diff --git a/tests/settings.py b/tests/settings.py
new file mode 100644
index 0000000..5d966e5
--- /dev/null
+++ b/tests/settings.py
@@ -0,0 +1,55 @@
+DATABASES = {
+    'default': {
+        'ENGINE': 'django.db.backends.sqlite3',
+        'NAME': 'test_db.sqlite'
+    }
+}
+
+MIDDLEWARE_CLASSES = (
+    'django.contrib.sessions.middleware.SessionMiddleware',
+    'django.middleware.common.CommonMiddleware',
+    'django.middleware.csrf.CsrfViewMiddleware',
+    'django.contrib.auth.middleware.AuthenticationMiddleware',
+    'django.contrib.messages.middleware.MessageMiddleware',
+    'django.middleware.clickjacking.XFrameOptionsMiddleware',
+)
+
+TEMPLATE_CONTEXT_PROCESSORS = (
+    'django.contrib.auth.context_processors.auth',
+    'django.core.context_processors.debug',
+    'django.core.context_processors.i18n',
+    'django.core.context_processors.media',
+    'django.core.context_processors.request',
+    'django.core.context_processors.static',
+    'django.core.context_processors.tz',
+)
+
+INSTALLED_APPS = (
+    'django.contrib.admin',
+    'django.contrib.auth',
+    'django.contrib.contenttypes',
+    'django.contrib.sessions',
+    'django.contrib.messages',
+    'django.contrib.staticfiles',
+    'recurrence',
+    'tests',
+)
+
+# ROOT_URLCONF = 'tests.urls'
+
+PASSWORD_HASHERS = (
+    'django.contrib.auth.hashers.MD5PasswordHasher',
+    'django.contrib.auth.hashers.SHA1PasswordHasher',
+)
+
+STATIC_URL = '/fakestatictrees/'
+MEDIA_ROOT = 'tests/testmedia/'
+
+TIME_ZONE = 'Europe/London'
+LANGUAGE_CODE = 'en-us'
+SITE_ID = 1
+USE_I18N = True
+USE_L10N = True
+USE_TZ = True
+SECRET_KEY = 'thisbagismadefromrecycledmaterial'
+TEMPLATE_DEBUG = True
diff --git a/tests/test_exclusions.py b/tests/test_exclusions.py
new file mode 100644
index 0000000..dd41ad1
--- /dev/null
+++ b/tests/test_exclusions.py
@@ -0,0 +1,83 @@
+from datetime import datetime
+from recurrence import Recurrence, Rule
+import recurrence
+
+
+def test_exclusion_date():
+    rule = Rule(
+        recurrence.DAILY
+    )
+
+    pattern = Recurrence(
+        dtstart=datetime(2014, 1, 2, 0, 0, 0),
+        dtend=datetime(2014, 1, 4, 0, 0, 0),
+        rrules=[rule],
+        exdates=[
+            datetime(2014, 1, 3, 0, 0, 0)
+        ]
+    )
+
+    occurrences = [
+        instance for instance in
+        pattern.occurrences()
+    ]
+
+    assert occurrences == [
+        datetime(2014, 1, 2, 0, 0, 0),
+        datetime(2014, 1, 4, 0, 0, 0),
+    ]
+
+    assert 2 == pattern.count()
+
+
+def test_exclusion_date_no_limits():
+    pattern = Recurrence(
+        rdates=[
+            datetime(2014, 1, 1, 0, 0, 0),
+            datetime(2014, 1, 2, 0, 0, 0),
+        ],
+        exdates=[
+            datetime(2014, 1, 2, 0, 0, 0)
+        ]
+    )
+
+    occurrences = [
+        instance for instance in
+        pattern.occurrences()
+    ]
+
+    assert occurrences == [
+        datetime(2014, 1, 1, 0, 0, 0),
+    ]
+
+    assert 1 == pattern.count()
+
+
+def test_exclusion_rule():
+    inclusion_rule = Rule(
+        recurrence.DAILY
+    )
+
+    exclusion_rule = Rule(
+        recurrence.WEEKLY,
+        byday=recurrence.THURSDAY
+    )
+
+    pattern = Recurrence(
+        dtstart=datetime(2014, 1, 2, 0, 0, 0),
+        dtend=datetime(2014, 1, 4, 0, 0, 0),
+        rrules=[inclusion_rule],
+        exrules=[exclusion_rule]
+    )
+
+    occurrences = [
+        instance for instance in
+        pattern.occurrences()
+    ]
+
+    assert occurrences == [
+        datetime(2014, 1, 3, 0, 0, 0),
+        datetime(2014, 1, 4, 0, 0, 0),
+    ]
+
+    assert 2 == pattern.count()
diff --git a/tests/test_fields.py b/tests/test_fields.py
new file mode 100644
index 0000000..33d59ae
--- /dev/null
+++ b/tests/test_fields.py
@@ -0,0 +1,159 @@
+from datetime import datetime
+from django import forms
+from recurrence import Recurrence, Rule
+from recurrence.forms import RecurrenceField
+import pytest
+import recurrence
+
+
+def test_clean_normal_value():
+    field = RecurrenceField()
+    value = "RRULE:FREQ=WEEKLY;BYDAY=TU"
+
+    obj = field.clean(value)
+
+    assert len(obj.rrules) == 1
+    assert obj.rrules[0].to_text() == "weekly, each Tuesday"
+
+
+def test_clean_invalid_value():
+    field = RecurrenceField()
+    value = "RRULE:FREQS=WEEKLY"
+
+    with pytest.raises(forms.ValidationError) as e:
+        field.clean(value)
+    assert e.value.messages[0] == "bad parameter: FREQS"
+
+
+def test_strip_dtstart_and_dtend_if_required():
+    rule = Rule(
+        recurrence.WEEKLY
+    )
+
+    limits = Recurrence(
+        dtstart=datetime(2014, 1, 1, 0, 0, 0),
+        dtend=datetime(2014, 2, 3, 0, 0, 0),
+        rrules=[rule]
+    )
+
+    value = recurrence.serialize(limits)
+
+    field = RecurrenceField()
+    cleaned_value = field.clean(value)
+    assert cleaned_value == limits
+    assert cleaned_value.dtstart == datetime(2014, 1, 1, 0, 0, 0)
+    assert cleaned_value.dtend == datetime(2014, 2, 3, 0, 0, 0)
+
+    field = RecurrenceField(accept_dtstart=False, accept_dtend=False)
+    cleaned_value = field.clean(value)
+    assert cleaned_value != limits
+    assert cleaned_value.dtstart is None
+    assert cleaned_value.dtend is None
+
+
+def test_check_max_rrules():
+    rule = Rule(
+        recurrence.WEEKLY
+    )
+
+    limits = Recurrence(
+        rrules=[rule]
+    )
+
+    value = recurrence.serialize(limits)
+
+    field = RecurrenceField(max_rrules=0)
+    with pytest.raises(forms.ValidationError) as e:
+        field.clean(value)
+    assert e.value.messages[0] == "Max rules exceeded. The limit is 0"
+
+
+def test_check_max_exrules():
+    rule = Rule(
+        recurrence.WEEKLY
+    )
+
+    limits = Recurrence(
+        exrules=[rule]
+    )
+
+    value = recurrence.serialize(limits)
+
+    field = RecurrenceField(max_exrules=0)
+    with pytest.raises(forms.ValidationError) as e:
+        field.clean(value)
+    assert e.value.messages[0] == ("Max exclusion rules exceeded. "
+                                   "The limit is 0")
+
+
+def test_check_max_rdates():
+    limits = Recurrence(
+        rdates=[
+            datetime(2014, 1, 1, 0, 0, 0),
+            datetime(2014, 1, 2, 0, 0, 0),
+        ]
+    )
+
+    value = recurrence.serialize(limits)
+
+    field = RecurrenceField(max_rdates=2)
+    field.clean(value)
+
+    field = RecurrenceField(max_rdates=1)
+    with pytest.raises(forms.ValidationError) as e:
+        field.clean(value)
+    assert e.value.messages[0] == "Max dates exceeded. The limit is 1"
+
+
+def test_check_max_exdates():
+    limits = Recurrence(
+        exdates=[
+            datetime(2014, 1, 1, 0, 0, 0),
+            datetime(2014, 1, 2, 0, 0, 0),
+        ]
+    )
+
+    value = recurrence.serialize(limits)
+
+    field = RecurrenceField(max_exdates=2)
+    field.clean(value)
+
+    field = RecurrenceField(max_exdates=1)
+    with pytest.raises(forms.ValidationError) as e:
+        field.clean(value)
+    assert e.value.messages[0] == ("Max exclusion dates exceeded. "
+                                   "The limit is 1")
+
+
+def test_check_allowable_frequencies():
+    rule = Rule(
+        recurrence.WEEKLY
+    )
+
+    limits = Recurrence(
+        rrules=[rule]
+    )
+
+    value = recurrence.serialize(limits)
+
+    field = RecurrenceField(frequencies=[
+        recurrence.WEEKLY
+    ])
+    field.clean(value)
+
+    field = RecurrenceField(frequencies=[
+        recurrence.YEARLY
+    ])
+    with pytest.raises(forms.ValidationError) as e:
+        field.clean(value)
+    assert e.value.messages[0] == "Invalid frequency."
+
+    limits = Recurrence(
+        exrules=[rule]
+    )
+
+    value = recurrence.serialize(limits)
+
+    with pytest.raises(forms.ValidationError) as e:
+        field.clean(value)
+    assert e.value.messages[0] == "Invalid frequency."
diff --git a/tests/test_magic_methods.py b/tests/test_magic_methods.py
new file mode 100644
index 0000000..f76811a
--- /dev/null
+++ b/tests/test_magic_methods.py
@@ -0,0 +1,63 @@
+from datetime import datetime
+from recurrence import Recurrence, Rule
+import recurrence
+
+
+def test_truthiness_with_single_rrule():
+    rule = Rule(
+        recurrence.DAILY
+    )
+
+    object = Recurrence(
+        rrules=[rule]
+    )
+
+    assert bool(object)
+
+
+def test_truthiness_with_single_exrule():
+    rule = Rule(
+        recurrence.DAILY
+    )
+
+    object = Recurrence(
+        exrules=[rule]
+    )
+
+    assert bool(object)
+
+
+def test_truthiness_with_single_rdate():
+    object = Recurrence(
+        rdates=[datetime(2014, 12, 31, 0, 0, 0)]
+    )
+
+    assert bool(object)
+
+
+def test_truthiness_with_single_exdate():
+    object = Recurrence(
+        exdates=[datetime(2014, 12, 31, 0, 0, 0)]
+    )
+
+    assert bool(object)
+
+
+def test_truthiness_with_dtstart():
+    object = Recurrence(
+        dtstart=datetime(2014, 12, 31, 0, 0, 0)
+    )
+
+    assert bool(object)
+
+
+def test_truthiness_with_dtend():
+    object = Recurrence(
+        dtend=datetime(2014, 12, 31, 0, 0, 0)
+    )
+
+    assert bool(object)
+
+
+def test_falsiness_with_empty_recurrence_object():
+    assert not bool(Recurrence())
diff --git a/tests/test_managers_recurrence.py b/tests/test_managers_recurrence.py
new file mode 100644
index 0000000..8854079
--- /dev/null
+++ b/tests/test_managers_recurrence.py
@@ -0,0 +1,136 @@
+from datetime import datetime
+from django.utils.timezone import make_aware
+from recurrence import choices
+from recurrence.models import Date, Recurrence, Rule
... 1041 lines suppressed ...

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/django-recurrence.git



More information about the Python-modules-commits mailing list