Skip to content

Commit

Permalink
Merge with master
Browse files Browse the repository at this point in the history
  • Loading branch information
jaraco committed Aug 28, 2014
2 parents 8007d28 + 61fc0ee commit 41919d6
Show file tree
Hide file tree
Showing 14 changed files with 4,061 additions and 133 deletions.
15 changes: 13 additions & 2 deletions CHANGELOG
@@ -1,10 +1,21 @@
CHANGELOG
=========

0.2 (unreleased)
0.3 (unreleased)
----------------

- Nothing changed yet.
- Germany calendar added, thx to @rndusr


0.2.0 (2014-07-15)
------------------

- How to contribute documentation,
- Added Belgium, European Central Bank, Sweden, every specific calendar in the
United States of America, Canada.
- BUGFIX: fixed a corpus christi bug. This day used to be included in every
ChristianMixin calendar, except noticed otherwise. Now it's not included by
default and should be set to "True" when needed.


0.1 (2014-02-17)
Expand Down
206 changes: 206 additions & 0 deletions CONTRIBUTING.rst
@@ -0,0 +1,206 @@
=========================
Contribute to Workalendar
=========================

Use it (and test it)
====================

If you are using ``workalendar``, you are already contributing to it. As long
as you are able to check its result, compare the designated working days and
holidays to the reality, and make sure these are right, you're helping.

If any of the computed holidays for the country / area your are using is
**wrong**, please report
`it using the Github issues <https://github.com/novapost/workalendar/issues>`_.

Report an issue
===============

If you think you've found a bug you can report an issue. In order to help us
sort this out, please follow the guidelines:

* Tell us which ``workalendar`` version (master, PyPI release) you are using.
* Tell us which Python version you are using, and your platform.
* Give us extensive details on the country / area Calendar, the exact date(s) that was (were) computed and the one(s) that should have been the correct result.
* If possible, please provide us a reliable source about the designated country / area calendar, where we could effectively check that we were wrong about a date, and giving us a way to patch our code properly so we can fix the bug.


Adding new calendars
====================

Since ``workalendar`` is mainly built around configuration variables and generic
methods, it's not that difficult to add a calendar to our codebase. A few
**mandatory** steps should be observed:

1. Fork the repository and create a new branch named after the calendar you want to implement,
2. Add a test class to the workalendar test suite that checks holidays,
3. Implement the class using the core class APIs as much as possible. Test it until all tests pass.
4. Make a nice pull-request we'll be glad to review and merge when it's perfect.

.. note::

Please respect the PEP8 convention, otherwise your PR won't be accepted.

Example
-------

Let's assume you want to include the holidays of the magic (fictional) kingdom
of *"Zhraa"*, which has a few holidays of different kind.

For the sake of the example, it has the following specs:

* it's a Gregorian-based Calendar (i.e. the Western European / American one),
* even if the King is not versed into religions, the kingdom includes a few Christian holidays,
* even if you never knew about it, it is set in Oceania,

Here is a list of the holidays in *Zhraa*:

* January 1st, New year's Day,
* May 1st, Labour day,
* Easter Monday, which is variable (from March to May),
* The first monday in June, to celebrate the birth of the Founder of the Kingdom, Zhraa (nobody knows the exact day he was born, so this day was chosen as a convention),
* The birthday of the King, August 2nd.
* Christmas Day, Dec 25th.


Getting ready
#############

You'll need to install ``workalendar`` dependencies beforehand. What's great is
that you'll use virtualenv to set it up. Or even better: ``virtualenvwrapper``.
Just go in your working copy (cloned from github) of workalendar and type, for
example::

mkvirtualenv WORKALENDAR
pip install -e ./


Test-driven start
#################


Let's prepare the Zhraa class. In the ``workalendar/oceania.py`` file, add
a class like this::

class Zhraa(WesternCalendar):
pass


Now, we're building a test class. Edit the ``workalendar/tests/test_oceania.py``
file and add the following code::

from workalendar.oceania import Zhraa
# snip...

class ZhraaTest(GenericCalendarTest):
cal_class = Zhraa

def test_year_2014(self):
holidays = self.cal.holidays_set(2014)
self.assertIn(date(2014, 1, 1), holidays) # new year
self.assertIn(date(2014, 5, 1), holidays) # labour day
self.assertIn(date(2014, 8, 2), holidays) # king birthday
self.assertIn(date(2014, 12, 25), holidays) # Xmas
# variable days
self.assertIn(date(2014, 4, 21), holidays) # easter monday
self.assertIn(date(2014, 6, 2), holidays) # First MON in June

of course, if you run the test using the ``tox`` or ``nosetests`` command,
this will fail, since we haven't implemented anything yet.

Install tox using the following command::

workon WORKALENDAR
pip install tox

With the ``WesternCalendar`` base class you have at least one holiday as a
bonus: the New year's day, which is commonly a holiday.

Add fixed days
##############

::

class Zhraa(WesternCalendar):
FIXED_HOLIDAYS = WesternCalendar.FIXED_HOLIDAYS + (
(5, 1, "Labour Day"),
(8, 2, "King Birthday"),
)

Now we've got 3 holidays out of 6.

Add religious holidays
######################

Using ChristianMixin as a base to our Zhraa class will instantly add Christmas
Day as a holiday. Now we can add Easter monday just by triggering the correct
flag.

::

class Zhraa(WesternCalendar, ChristianMixin):
include_easter_monday = True
FIXED_HOLIDAYS = WesternCalendar.FIXED_HOLIDAYS + (
(5, 1, "Labour Day"),
(8, 2, "King Birthday"),
)

Almost there, 5 holidays out of 6.

Add variable "non-usual" holidays
#################################

There are many static methods that will grant you a clean access to variable
days computation. It's very easy to add days like the "Birthday of the Founder"::


class Zhraa(WesternCalendar, ChristianMixin):
include_easter_monday = True
FIXED_HOLIDAYS = WesternCalendar.FIXED_HOLIDAYS + (
(5, 1, "Labour Day"),
(8, 2, "King Birthday"),
)

def get_variable_days(self, year):
# usual variable days
days = super(Zhraa, self).get_variable_days(year)

days.append(
(Zhraa.get_nth_weekday_in_month(year, 6, MON),
'Day of the Founder'),
)
return days

.. note::

Please mind that the returned "variable_days" is a list of tuples. The first
item being a date object (in the Python ``datetime.date`` sense) and the
second one is the label string.


There you are. Commit with a nice commit message, test, make sure it works for
the other years as well and you're almost there.

The final steps
###############

Do not forget to:

1. put the appropriate doctring in the Calendar class.
2. add your calendar in the ``README.rst`` file, included in the appropriate continent.

.. note::

We're planning to build a complete documentation for the other cases
(special holiday rules, other calendar types, other religions, etc). But
with this tutorial you're sorted for a lot of other calendars.


Other code contributions
========================

There are dozens of calendars all over the world. We'd appreciate you to
contribute to the core of the library by adding some new Mixins or Calendars.

Bear in mind that the code you'd provide **must** be tested using unittests
before you submit your pull-request.
13 changes: 12 additions & 1 deletion README.rst
Expand Up @@ -71,10 +71,13 @@ Available Calendars
Europe
------

* Belgium
* Czech Republic
* European Central Bank
* Finland
* France
* France (Alsace / Moselle)
* Germany
* Greece
* Hungary
* Iceland
Expand All @@ -91,7 +94,8 @@ America
* Chile
* Mexico
* Panama
* United States of America (only the federal state holidays at the moment)
* United States of America (including state holidays)
* Canada (including provincial and territory holidays)

Asia
----
Expand Down Expand Up @@ -128,6 +132,13 @@ the same official day decided by religious authorities, and this may vary
country by country. Whenever it's possible, try to adjust your results with
the official data provided by the adequate authorities.

Contributing
============

Please read our `CONTRIBUTING.rst <https://github.com/novapost/workalendar/blob/master/CONTRIBUTING.rst>`_
document to discover how you can contribute to ``workalendar``. Pull-requests
are very welcome.

License
=======

Expand Down
52 changes: 27 additions & 25 deletions setup.py
Expand Up @@ -25,35 +25,37 @@ def read_relative_file(filename):
'pytz',
'pyCalverter',
]
__VERSION__ = '0.2-dev'
__VERSION__ = '0.3-dev'

if PY2:
REQUIREMENTS.append('pyephem')
else:
REQUIREMENTS.append('ephem')

params = dict(
name=NAME,
description=DESCRIPTION,
packages=['workalendar'],
version=__VERSION__,
long_description=read_relative_file('README.rst'),
author='Bruno Bord',
author_email='bruno.bord@novapost.fr',
url='https://github.com/novapost/workalendar',
license='MIT License',
include_package_data=True,
install_requires=REQUIREMENTS,
zip_safe=False,
classifiers=[
'Development Status :: 4 - Beta',
'Intended Audience :: Developers',
'License :: OSI Approved :: MIT License',
'Programming Language :: Python',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.3',
],
)

if __name__ == '__main__':
setup(
name=NAME,
description=DESCRIPTION,
packages=['workalendar'],
version=__VERSION__,
long_description=read_relative_file('README.rst'),
author='Bruno Bord',
author_email='bruno.bord@novapost.fr',
url='https://github.com/novapost/workalendar',
license='MIT License',
include_package_data=True,
install_requires=REQUIREMENTS,
zip_safe=False,
classifiers=(
'Development Status :: 4 - Beta',
'Intended Audience :: Developers',
'License :: OSI Approved :: MIT License',
'Programming Language :: Python',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.3',
)
)
setup(**params)

0 comments on commit 41919d6

Please sign in to comment.