pax_global_header00006660000000000000000000000064134366302270014520gustar00rootroot0000000000000052 comment=ab8cb2cdd1d1847e7504d9a2b6dca953ed5be97d pyluach-1.0.1/000077500000000000000000000000001343663022700131645ustar00rootroot00000000000000pyluach-1.0.1/.gitignore000066400000000000000000000001021343663022700151450ustar00rootroot00000000000000.* !.gitignore *.pyc *~ ENV* *egg* *build* *.whl dist/* *htmlcov* pyluach-1.0.1/.travis.yml000066400000000000000000000002761343663022700153020ustar00rootroot00000000000000language: python python: - "2.7" - "3.4" - "3.5" - "3.6" install: - pip install coveralls pytest-cov script: pytest --cov-report= --cov=pyluach tests/ after_success: coveralls pyluach-1.0.1/README.rst000066400000000000000000000034521343663022700146570ustar00rootroot00000000000000pyluach ======== .. image:: https://readthedocs.org/projects/pyluach/badge/?version=latest :target: http://pyluach.readthedocs.io/en/latest/?badge=latest :alt: Documentation Status .. image:: https://travis-ci.org/simlist/pyluach.svg?branch=master :target: https://travis-ci.org/simlist/pyluach .. image:: https://coveralls.io/repos/github/simlist/pyluach/badge.svg?branch=master :target: https://coveralls.io/github/simlist/pyluach?branch=master Pyluach is a Python package for manipulating Hebrew (Jewish) calendar dates and Hebrew-Gregorian conversions. Features --------- * Conversion between Hebrew and Gregorian dates * Finding the difference between two dates * Finding a date at a given duration from the given date * Rich comparisons between dates * Finding the weekday of a given date * Finding the weekly Parsha reading of a given date Installation ------------- Use ``pip install pyluach``. Typical use ------------ :: >>> from pyluach import dates, hebrewcal, parshios >>> today = dates.HebrewDate.today() >>> lastweek_gregorian = (today - 7).to_greg() >>> lastweek_gregorian < today True >>> today - lastweek_gregorian 7 >>> greg = GregorianDate(1986, 3, 21) >>> heb = HebrewDate(5746, 13, 10) >>> greg == heb True >>> for month in hebrewcal.Year(5774).itermonths(): ... print(month.name) Tishrei Cheshvan ... >>> date = dates.GregorianDate(2010, 10, 6) >>> print(parshios.getparsha(date)) [0] >>> print(parshios.getparsha_string(date)) Beraishis Documentation ------------- Documentation for pyluach can be found at https://readthedocs.org/projects/pyluach/. Contact -------- For questions and comments feel free to contact me at simlist@gmail.com. License -------- Pyluach is licensed under the MIT license. pyluach-1.0.1/docs/000077500000000000000000000000001343663022700141145ustar00rootroot00000000000000pyluach-1.0.1/docs/Makefile000066400000000000000000000151621343663022700155610ustar00rootroot00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # User-friendly check for sphinx-build ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) endif # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" @echo " text to make text files" @echo " man to make manual pages" @echo " texinfo to make Texinfo files" @echo " info to make Texinfo files and run them through makeinfo" @echo " gettext to make PO message catalogs" @echo " changes to make an overview of all changed/added/deprecated items" @echo " xml to make Docutils-native XML files" @echo " pseudoxml to make pseudoxml-XML files for display purposes" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: rm -rf $(BUILDDIR)/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/luachcal.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/luachcal.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/luachcal" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/luachcal" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." latexpdfja: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through platex and dvipdfmx..." $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." texinfo: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." info: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo "Running Texinfo files through makeinfo..." make -C $(BUILDDIR)/texinfo info @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." gettext: $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale @echo @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." xml: $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml @echo @echo "Build finished. The XML files are in $(BUILDDIR)/xml." pseudoxml: $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml @echo @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." pyluach-1.0.1/docs/conf.py000066400000000000000000000250711343663022700154200ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # luachcal documentation build configuration file, created by # sphinx-quickstart on Wed Jan 21 21:24:38 2015. # # This file is execfile()d with the current directory set to its # containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys import os # 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 ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ 'sphinx.ext.autodoc', 'sphinx.ext.viewcode', 'sphinx.ext.autosummary', 'sphinxcontrib.napoleon', # 'numpydoc', ] # Napoleon settings napoleon_include_special_with_doc = False # Numpydoc settings (not using for now) # numpydoc_class_members_toctree = False autodoc_default_flags = ['members', 'inherited-members', 'show-inheritance'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = u'pyluach' copyright = u'2016, Simlist' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = '1.0' # The full version, including alpha/beta/rc tags. release = '1.0.1' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = ['_build'] # The reST default role (used for this markup: `text`) to use for all # documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # If true, keep warnings as "system message" paragraphs in the built documents. #keep_warnings = False # -- Options for HTML output ---------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # See http://docs.readthedocs.org/en/latest/theme.html for why this code. on_rtd = os.environ.get('READTHEDOCS', None) == 'True' if not on_rtd: import sphinx_rtd_theme html_theme = 'sphinx_rtd_theme' html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied # directly to the root of the documentation. #html_extra_path = [] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_domain_indices = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. #html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. #html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'pyluachdoc' # -- Options for LaTeX output --------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). #'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). #'pointsize': '10pt', # Additional stuff for the LaTeX preamble. #'preamble': '', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ ('index', 'luachcal.tex', u'luachcal Documentation', u'Author', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # If true, show page references after internal links. #latex_show_pagerefs = False # If true, show URL addresses after external links. #latex_show_urls = False # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_domain_indices = True # -- Options for manual page output --------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'luachcal', u'luachcal Documentation', [u'Author'], 1) ] # If true, show URL addresses after external links. #man_show_urls = False # -- Options for Texinfo output ------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ ('index', 'luachcal', u'luachcal Documentation', u'Author', 'luachcal', 'One line description of project.', 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. #texinfo_appendices = [] # If false, no module index is generated. #texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. #texinfo_show_urls = 'footnote' # If true, do not generate a @detailmenu in the "Top" node's menu. #texinfo_no_detailmenu = False # -- Options for Epub output ---------------------------------------------- # Bibliographic Dublin Core info. epub_title = u'pyluach' epub_author = u'Simlist' epub_publisher = u'Author' epub_copyright = u'2016, Simlist' # The basename for the epub file. It defaults to the project name. #epub_basename = u'luachcal' # The HTML theme for the epub output. Since the default themes are not optimized # for small screen space, using the same theme for HTML and epub output is # usually not wise. This defaults to 'epub', a theme designed to save visual # space. #epub_theme = 'epub' # The language of the text. It defaults to the language option # or en if the language is not set. #epub_language = '' # The scheme of the identifier. Typical schemes are ISBN or URL. #epub_scheme = '' # The unique identifier of the text. This can be a ISBN number # or the project homepage. #epub_identifier = '' # A unique identification for the text. #epub_uid = '' # A tuple containing the cover image and cover page html template filenames. #epub_cover = () # A sequence of (type, uri, title) tuples for the guide element of content.opf. #epub_guide = () # HTML files that should be inserted before the pages created by sphinx. # The format is a list of tuples containing the path and title. #epub_pre_files = [] # HTML files shat should be inserted after the pages created by sphinx. # The format is a list of tuples containing the path and title. #epub_post_files = [] # A list of files that should not be packed into the epub file. epub_exclude_files = ['search.html'] # The depth of the table of contents in toc.ncx. #epub_tocdepth = 3 # Allow duplicate toc entries. #epub_tocdup = True # Choose between 'default' and 'includehidden'. #epub_tocscope = 'default' # Fix unsupported image types using the PIL. #epub_fix_images = False # Scale large images. #epub_max_image_width = 0 # How to display URL addresses: 'footnote', 'no', or 'inline'. #epub_show_urls = 'inline' # If false, no index is generated. #epub_use_index = True pyluach-1.0.1/docs/index.rst000066400000000000000000000006661343663022700157650ustar00rootroot00000000000000.. pyluach documentation master file, created by sphinx-quickstart on Wed Jan 21 21:24:38 2015. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. Welcome to pyluach's documentation! ==================================== Contents: .. toctree:: :maxdepth: 4 pyluach Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` pyluach-1.0.1/docs/make.bat000066400000000000000000000144771343663022700155360ustar00rootroot00000000000000@ECHO OFF REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set BUILDDIR=_build set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . set I18NSPHINXOPTS=%SPHINXOPTS% . if NOT "%PAPER%" == "" ( set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% ) if "%1" == "" goto help if "%1" == "help" ( :help echo.Please use `make ^` where ^ is one of echo. html to make standalone HTML files echo. dirhtml to make HTML files named index.html in directories echo. singlehtml to make a single large HTML file echo. pickle to make pickle files echo. json to make JSON files echo. htmlhelp to make HTML files and a HTML help project echo. qthelp to make HTML files and a qthelp project echo. devhelp to make HTML files and a Devhelp project echo. epub to make an epub echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter echo. text to make text files echo. man to make manual pages echo. texinfo to make Texinfo files echo. gettext to make PO message catalogs echo. changes to make an overview over all changed/added/deprecated items echo. xml to make Docutils-native XML files echo. pseudoxml to make pseudoxml-XML files for display purposes echo. linkcheck to check all external links for integrity echo. doctest to run all doctests embedded in the documentation if enabled goto end ) if "%1" == "clean" ( for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i del /q /s %BUILDDIR%\* goto end ) %SPHINXBUILD% 2> nul if errorlevel 9009 ( echo. echo.The 'sphinx-build' command was not found. Make sure you have Sphinx echo.installed, then set the SPHINXBUILD environment variable to point echo.to the full path of the 'sphinx-build' executable. Alternatively you echo.may add the Sphinx directory to PATH. echo. echo.If you don't have Sphinx installed, grab it from echo.http://sphinx-doc.org/ exit /b 1 ) if "%1" == "html" ( %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/html. goto end ) if "%1" == "dirhtml" ( %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. goto end ) if "%1" == "singlehtml" ( %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. goto end ) if "%1" == "pickle" ( %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the pickle files. goto end ) if "%1" == "json" ( %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the JSON files. goto end ) if "%1" == "htmlhelp" ( %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run HTML Help Workshop with the ^ .hhp project file in %BUILDDIR%/htmlhelp. goto end ) if "%1" == "qthelp" ( %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run "qcollectiongenerator" with the ^ .qhcp project file in %BUILDDIR%/qthelp, like this: echo.^> qcollectiongenerator %BUILDDIR%\qthelp\luachcal.qhcp echo.To view the help file: echo.^> assistant -collectionFile %BUILDDIR%\qthelp\luachcal.ghc goto end ) if "%1" == "devhelp" ( %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp if errorlevel 1 exit /b 1 echo. echo.Build finished. goto end ) if "%1" == "epub" ( %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub if errorlevel 1 exit /b 1 echo. echo.Build finished. The epub file is in %BUILDDIR%/epub. goto end ) if "%1" == "latex" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex if errorlevel 1 exit /b 1 echo. echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. goto end ) if "%1" == "latexpdf" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex cd %BUILDDIR%/latex make all-pdf cd %BUILDDIR%/.. echo. echo.Build finished; the PDF files are in %BUILDDIR%/latex. goto end ) if "%1" == "latexpdfja" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex cd %BUILDDIR%/latex make all-pdf-ja cd %BUILDDIR%/.. echo. echo.Build finished; the PDF files are in %BUILDDIR%/latex. goto end ) if "%1" == "text" ( %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text if errorlevel 1 exit /b 1 echo. echo.Build finished. The text files are in %BUILDDIR%/text. goto end ) if "%1" == "man" ( %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man if errorlevel 1 exit /b 1 echo. echo.Build finished. The manual pages are in %BUILDDIR%/man. goto end ) if "%1" == "texinfo" ( %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo if errorlevel 1 exit /b 1 echo. echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. goto end ) if "%1" == "gettext" ( %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale if errorlevel 1 exit /b 1 echo. echo.Build finished. The message catalogs are in %BUILDDIR%/locale. goto end ) if "%1" == "changes" ( %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes if errorlevel 1 exit /b 1 echo. echo.The overview file is in %BUILDDIR%/changes. goto end ) if "%1" == "linkcheck" ( %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck if errorlevel 1 exit /b 1 echo. echo.Link check complete; look for any errors in the above output ^ or in %BUILDDIR%/linkcheck/output.txt. goto end ) if "%1" == "doctest" ( %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest if errorlevel 1 exit /b 1 echo. echo.Testing of doctests in the sources finished, look at the ^ results in %BUILDDIR%/doctest/output.txt. goto end ) if "%1" == "xml" ( %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml if errorlevel 1 exit /b 1 echo. echo.Build finished. The XML files are in %BUILDDIR%/xml. goto end ) if "%1" == "pseudoxml" ( %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml if errorlevel 1 exit /b 1 echo. echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. goto end ) :end pyluach-1.0.1/docs/pyluach.rst000066400000000000000000000007001343663022700163100ustar00rootroot00000000000000pyluach package ================ .. automodule:: pyluach :members: Submodules ---------- pyluach.dates module --------------------- .. automodule:: pyluach.dates :members: :show-inheritance: pyluach.hebrewcal module ------------------------- .. automodule:: pyluach.hebrewcal :members: :show-inheritance: pyluach.parshios module ------------------------ .. automodule:: pyluach.parshios :members: :show-inheritance: pyluach-1.0.1/docs/requirements.txt000066400000000000000000000000571343663022700174020ustar00rootroot00000000000000sphinxcontrib-napoleon sphinx_rtd_theme pyluachpyluach-1.0.1/license.txt000066400000000000000000000021431343663022700153470ustar00rootroot00000000000000The MIT License (MIT) [OSI Approved License] The MIT License (MIT) Copyright (c) 2014 Meir S. List 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.pyluach-1.0.1/pyluach/000077500000000000000000000000001343663022700146315ustar00rootroot00000000000000pyluach-1.0.1/pyluach/__init__.py000066400000000000000000000001521343663022700167400ustar00rootroot00000000000000"""Pyluach is a Python package for manipulating Hebrew calendar dates and Hebrew-Gregorian conversions."""pyluach-1.0.1/pyluach/dates.py000066400000000000000000000507311343663022700163110ustar00rootroot00000000000000"""The dates module implements classes for representing and manipulating several date types. Classes ------- * BaseDate * CalendarDateMixin * JulianDay * GregorianDate * HebrewDate Note ---- All instances of the classes in this module should be treated as read only. No attributes should be changed once they're created. """ from __future__ import division from datetime import date from numbers import Number from pyluach.utils import memoize class BaseDate(object): """BaseDate is a base class for all date types. It provides the following arithmetic and comparison operators common to all child date types. =================== ============================================= Operation Result =================== ============================================= d2 = date1 + int New date ``int`` days after date1 d2 = date1 - int New date ``int`` days before date1 int = date1 - date2 Integer equal to the absolute value of the difference between date1 and date2 date1 > date2 True if date1 occurs later than date2 date1 < date2 True if date1 occurs earlier than date2 date1 == date2 True if date1 occurs on the same day as date2 date1 != date2 True if ``date1 == date2`` is False date1 >=, <= date2 True if both are True =================== ============================================= Any child of BaseDate that implements a ``jd`` attribute representing the Julian Day of that date can be compared to and diffed with any other valid date type. """ def __hash__(self): return hash(self.jd) def __add__(self, other): try: return JulianDay(self.jd + other)._to_x(self) except AttributeError: raise TypeError('You can only add a number to a date.') def __sub__(self, other): if isinstance(other, Number): return JulianDay(self.jd - other)._to_x(self) try: return abs(self.jd - other.jd) except AttributeError: raise TypeError("""You can only subtract a number or another date that has a "jd" attribute from a date""") def __eq__(self, other): try: if self.jd == other.jd: return True return False except AttributeError: raise TypeError(self._error_string) def __ne__(self, other): try: if self.jd != other.jd: return True return False except AttributeError: raise TypeError(self._error_string) def __lt__(self, other): try: if self.jd < other.jd: return True return False except AttributeError: raise TypeError(self._error_string) def __gt__(self, other): try: if self.jd > other.jd: return True return False except AttributeError: raise TypeError(self._error_string) def __le__(self, other): try: if self.jd <= other.jd: return True return False except AttributeError: raise TypeError(self._error_string) def __ge__(self, other): try: if self.jd >= other.jd: return True return False except AttributeError: raise TypeError(self._error_string) def shabbos(self): """Return the Shabbos on or following the date. Returns ------- Date Self if it's Shabbos or else the following Shabbos as the same date type as operated on. """ return self + (7 - self.weekday()) class CalendarDateMixin(object): """CalendarDateMixin is a mixin for Hebrew and Gregorian dates. Parameters ---------- Year : int Month : int day : int Attributes ---------- year : int month : int day : int jd : float The equivelant Julian day at midnight. """ def __init__(self, year, month, day, jd=None): """Initialize a calendar date.""" self.year = year self.month = month self.day = day self._jd = jd self. _error_string = ('''Only a date with a "jd" attribute can be compared to a {0}'''.format( self.__class__.__name__) ) def __repr__(self): return '{0}({1}, {2}, {3})'.format(self.__class__.__name__, self.year, self.month, self.day) def __str__(self): return '{0:04d}-{1:02d}-{2:02d}'.format(self.year, self.month, self.day) def __iter__(self): yield self.year yield self.month yield self.day def weekday(self): """Return day of week as an integer. Returns ------- int An integer representing the day of the week with Sunday as 1 through Saturday as 7. """ return int(self.jd+.5+1) % 7 + 1 def tuple(self): """Return date as tuple. Returns ------- tuple of ints A tuple of ints in the form ``(year, month, day)``. """ return (self.year, self.month, self.day) def dict(self): """Return the date as a dictionary. Returns ------- Dict A dictionary in the form ``{'year': int, 'month': int, 'day': int}``. """ return {'year': self.year, 'month': self.month, 'day': self.day} class JulianDay(BaseDate): """A JulianDay object represents a Julian Day at midnight. Parameters ---------- day : float or int The julian day. Note that Julian days start at noon so day number 10 is represented as 9.5 which is day 10 at midnight. Attributes ---------- day : float The Julian Day Number at midnight (as *n*.5) jd : float Alias for day. """ def __init__(self, day): """Initialize a JulianDay instance.""" if day-int(day) < .5: self.day = int(day) - .5 else: self.day = int(day) + .5 self.jd = self.day self._error_string = """Only a date with a "jd" attribute can be compared to a Julian Day instance.""" def __repr__(self): return 'JulianDay({0})'.format(self.day) def __str__(self): return str(self.day) def weekday(self): """Return weekday of date. Returns ------- int The weekday with Sunday as 1 through Saturday as 7. """ return (int(self.day+.5) + 1) % 7 + 1 @staticmethod def from_pydate(pydate): """Return a `JulianDay` from a python date object. Parameters ---------- pydate : datetime.date A python standard library ``datetime.date`` instance Returns ------- JulianDay """ return GregorianDate.from_pydate(pydate).to_jd() @staticmethod def today(): """Return instance of current Julian day from timestamp. Extends the built-in ``datetime.date.today()``. Returns ------- JulianDay A JulianDay instance representing the current Julian day from the timestamp. """ return GregorianDate.today().to_jd() def to_greg(self): """Convert JulianDay to a Gregorian Date. Returns ------- GregorianDate The equivalent Gregorian date instance. Notes ----- This method uses the Fliegel-Van Flandern algorithm. """ jd = int(self.day + .5) L = jd + 68569 n = 4*L // 146097 L = L - (146097*n + 3) // 4 i = (4000 * (L+1)) // 1461001 L = L - ((1461*i) // 4) + 31 j = (80*L) // 2447 day = L - 2447*j // 80 L = j // 11 month = j + 2 - 12*L year = 100 * (n-49) + i + L if year < 1: year -= 1 return GregorianDate(year, month, day, self.day) def to_heb(self): """ Convert to a Hebrew date. Returns ------- HebrewDate The equivalent Hebrew date instance. """ if self.day <= 347997: raise ValueError('Date is before creation') jd = int(self.day + .5) # Try to account for half day jd -= 347997 year = int(jd//365) + 2 ## try that to debug early years first_day = HebrewDate._elapsed_days(year) while first_day > jd: year -= 1 first_day = HebrewDate._elapsed_days(year) months = [7, 8, 9, 10, 11, 12, 13, 1, 2, 3, 4, 5, 6] if not HebrewDate._is_leap(year): months.remove(13) days_remaining = jd - first_day for month in months: if days_remaining >= HebrewDate._month_length(year, month): days_remaining -= HebrewDate._month_length(year, month) else: return HebrewDate(year, month, days_remaining + 1, self.day) def _to_x(self, type_): """Return a date object of the given type.""" if isinstance(type_, GregorianDate): return self.to_greg() elif isinstance(type_, HebrewDate): return self.to_heb() elif isinstance(type_, JulianDay): return self def to_pydate(self): """Convert to a datetime.date object. Returns ------- datetime.date A standard library ``datetime.date`` instance. """ return self.to_greg().to_pydate() class GregorianDate(BaseDate, CalendarDateMixin): """A GregorianDate object represents a Gregorian date (year, month, day). This is an idealized date with the current Gregorian calendar infinitely extended in both directions. Parameters ---------- year : int month : int day : int jd : float, optional This parameter should not be assigned manually. Attributes ---------- year : int month : int day : int jd : float(property) The corresponding Julian Day Number at midnight (as *n*.5). Warnings -------- Although B.C.E. dates are allowed, they should be treated as approximations as they may return inconsistent results when converting between date types and using arithmetic and comparison operators! """ def __init__(self, year, month, day, jd=None): """Initialize a GregorianDate. This initializer extends the CalendarDateMixin initializer adding in date validation specific to Gregorian dates. """ if month < 1 or month > 12: raise ValueError('{0} is an invalid month.'.format(str(month))) monthlength = self._monthlength(year, month) if day < 1 or day > monthlength: raise ValueError('Given month has {0} days.'.format(monthlength)) super(GregorianDate, self).__init__(year, month, day, jd) @property def jd(self): """Return the corresponding Julian day number. This property retrieves the corresponding Julian Day as a float if it was passed into the init method or already calculated, and if it wasn't, it calculates it and saves it for later retrievals and returns it. Returns ------- float The Julian day number at midnight. """ if self._jd is None: year = self.year month = self.month day = self.day if year < 0: year += 1 if month < 3: year -= 1 month += 12 month += 1 a = year // 100 b = 2 - a + a//4 self._jd = (int(365.25*year) + int(30.6001*month) + b + day + 1720994.5) return self._jd @staticmethod def from_pydate(pydate): """Return a `GregorianDate` instance from a python date object. Parameters ---------- pydate : datetime.date A python standard library ``datetime.date`` instance. Returns ------- GregorianDate """ return GregorianDate(*pydate.timetuple()[:3]) @staticmethod def today(): """Return a GregorianDate instance for the current day. This static method wraps the Python standard library's date.today() method to get the date from the timestamp. Returns ------- GregorianDate The current Gregorian date from the computer's timestamp. """ return GregorianDate.from_pydate(date.today()) @staticmethod def _is_leap(year): """Return True if year of date is a leap year, otherwise False.""" if year < 0: year += 1 if( (year % 4 == 0) and not (year % 100 == 0 and year % 400 != 0) ): return True return False def is_leap(self): """Return if the date is in a leap year Returns ------- bool True if the date is in a leap year, False otherwise. """ return self._is_leap(self.year) @classmethod def _monthlength(cls, year, month): if month in [1, 3, 5, 7, 8, 10, 12]: return 31 elif month != 2: return 30 else: return 29 if cls._is_leap(year) else 28 def to_jd(self): """Convert to a Julian day. Returns ------- JulianDay The equivalent JulianDay instance. """ return JulianDay(self.jd) def to_heb(self): """Convert to Hebrew date. Returns ------- HebrewDate The equivalent HebrewDate instance. """ return self.to_jd().to_heb() def to_pydate(self): """Convert to a standard library date. Returns ------- datetime.date The equivalent datetime.date instance. """ return date(*self.tuple()) class HebrewDate(BaseDate, CalendarDateMixin): """A class for manipulating Hebrew dates. Parameters ---------- year : int The Hebrew year. If the year is less than 1 it will raise a ValueError. month : int The Hebrew month starting with Nissan as 1 (and Tishrei as 7). If there is a second Adar in the year it is represented as 13. A month below 1 or above the last month will raise a ValueError. day : int The Hebrew day of the month. An invalid day will raise a ValueError. jd : float, optional This parameter should not be assigned manually. Attributes ---------- year : int month : int The Hebrew month starting with Nissan as 1 (and Tishrei as 7). If there is a second Adar it is represented as 13. day : int The day of the month. """ def __init__(self, year, month, day, jd=None): """Initialize a HebrewDate instance. This initializer extends the CalendarDateMixin adding validation specific to hebrew dates. """ if year < 1: raise ValueError('Date supplied is before creation.') if month < 1 or month > 13: raise ValueError('{0} is an invalid month.'.format(str(month))) if (not self._is_leap(year)) and month == 13: raise ValueError('{0} is not a leap year'.format(year)) monthlength = self._month_length(year, month) if day < 1 or day > monthlength: raise ValueError('Given month has {0} days.'.format(monthlength)) super(HebrewDate, self).__init__(year, month, day, jd) @property def jd(self): """Return the corresponding Julian day number. This property retrieves the corresponding Julian Day as a float if it was passed into the init method or already calculated, and if it wasn't, it calculates it, saves it for later retrievals, and returns it. Returns ------- float The Julian day number at midnight. """ if self._jd is None: months = [7, 8, 9, 10, 11, 12, 13, 1, 2, 3, 4, 5, 6] if not HebrewDate._is_leap(self.year): months.remove(13) jd = HebrewDate._elapsed_days(self.year) for m in months: if m != self.month: jd += HebrewDate._month_length(self.year, m) else: self._jd = jd + (self.day-1) + 347996.5 return self._jd @staticmethod def from_pydate(pydate): """Return a `HebrewDate` from a python date object. Parameters ---------- pydate : datetime.date A python standard library ``datetime.date`` instance Returns ------- HebrewDate """ return GregorianDate.from_pydate(pydate).to_heb() @staticmethod def today(): """Return HebrewDate instance for the current day. This static method wraps the Python standard library's ``date.today()`` method to get the date from the timestamp. Returns ------- HebrewDate The current Hebrew date from the computer's timestamp. Note ---- This method coverts the Gregorian date from the time stamp to a Hebrew date, so if it is after nightfall but before midnight you will have to add one day, ie. ``today = HebrewDate.today() + 1``. """ return GregorianDate.today().to_heb() def to_jd(self): """Convert to a Julian day. Returns ------- JulianDay The equivalent JulianDay instance. """ return JulianDay(self.jd) def to_greg(self): """Convert to a Gregorian date. Returns ------- GregorianDate The equivalent GregorianDate instance. """ return self.to_jd().to_greg() def to_pydate(self): """Convert to a standard library date. Returns ------- datetime.date The equivalent datetime.date instance. """ return self.to_greg().to_pydate() def to_heb(self): return self @staticmethod def _is_leap(year): if (((7*year) + 1) % 19) < 7: return True return False @classmethod @memoize(maxlen=100) def _elapsed_days(cls, year): months_elapsed = ( (235 * ((year-1) // 19)) + (12 * ((year-1) % 19)) + (7 * ((year-1) % 19) + 1) // 19 ) parts_elapsed = 204 + 793*(months_elapsed%1080) hours_elapsed = (5 + 12*months_elapsed + 793*(months_elapsed//1080) + parts_elapsed//1080) conjunction_day = 1 + 29*months_elapsed + hours_elapsed//24 conjunction_parts = 1080 * (hours_elapsed%24) + parts_elapsed%1080 if ( (conjunction_parts >= 19440) or ( (conjunction_day % 7 == 2) and (conjunction_parts >= 9924) and (not cls._is_leap(year)) ) or ( (conjunction_day % 7 == 1) and conjunction_parts >= 16789 and cls._is_leap(year - 1))): # if all that alt_day = conjunction_day + 1 else: alt_day = conjunction_day if (alt_day % 7) in (0, 3, 5): alt_day += 1 return alt_day @classmethod def _days_in_year(cls, year): return cls._elapsed_days(year + 1) - cls._elapsed_days(year) @classmethod def _long_cheshvan(cls, year): """Returns True if Cheshvan has 30 days""" return cls._days_in_year(year) % 10 == 5 @classmethod def _short_kislev(cls, year): """Returns True if Kislev has 29 days""" return cls._days_in_year(year) % 10 == 3 @classmethod def _month_length(cls, year, month): """Months start with Nissan (Nissan is 1 and Tishrei is 7)""" if month in [1, 3, 5, 7, 11]: return 30 elif month in [2, 4, 6, 10, 13]: return 29 elif month == 12: return 30 if cls._is_leap(year) else 29 elif month == 8: # if long Cheshvan return 30, else return 29 return 30 if cls._long_cheshvan(year) else 29 elif month == 9: # if short Kislev return 29, else return 30 return 29 if cls._short_kislev(year) else 30 pyluach-1.0.1/pyluach/hebrewcal.py000066400000000000000000000250041343663022700171400ustar00rootroot00000000000000from __future__ import unicode_literals from __future__ import division from collections import deque from numbers import Number from pyluach.dates import HebrewDate from pyluach.utils import memoize def _adjust_postponed(date): """Return actual date of fast day. For usual date of a fast day returns fast day adjusted for any postponements. """ if date.weekday() == 7: if date.month in [12, 13]: date -= 2 else: date += 1 return date @memoize(maxlen=50) def _fast_day_table(year): table = dict() workingdate = _adjust_postponed(HebrewDate(year, 7, 3)) table[workingdate] = 'Tzom Gedalia' workingdate = _adjust_postponed(HebrewDate(year, 10, 10)) table[workingdate] = '10 of Teves' month = 13 if Year(year).leap else 12 workingdate = _adjust_postponed(HebrewDate(year, month, 13)) table[workingdate] = 'Taanis Esther' workingdate = _adjust_postponed(HebrewDate(year, 4, 17)) table[workingdate] = '17 of Tamuz' workingdate = _adjust_postponed(HebrewDate(year, 5, 9)) table[workingdate] = '9 of Av' return table def holiday(date, israel=False): """Return Jewish holiday of given date. The holidays include the major and minor religious Jewish holidays including fast days. Parameters ---------- date : ``HebrewDate``, ``GregorianDate``, or ``JulianDay`` Any date that implements a ``to_heb()`` method which returns a ``HebrewDate`` can be used. israel : boolian, optional ``True`` if you want the holidays according to the israel schedule. Defaults to ``False``. Returns ------- str or ``None`` The name of the holiday or ``None`` if the given date is not a Jewish holiday. """ date = date.to_heb() year = date.year month = date.month day = date.day table = _fast_day_table(year) if date in table: return table[date] if month == 7: if day in range(1, 3): return 'Rosh Hashana' elif day == 10: return 'Yom Kippur' elif day in range(15, 22): return 'Succos' elif day == 22: return 'Shmini Atzeres' elif day == 23 and israel == False: return 'Simchas Torah' elif( (month == 9 and day in range(25, 30)) or date in [(HebrewDate(year, 9, 29) + n) for n in range(1, 4)] ): return 'Chanuka' elif month == 11 and day == 15: return "Tu B'shvat" elif month == 12: leap = HebrewDate._is_leap(year) if day == 14: return 'Purim Katan' if leap else 'Purim' if day == 15 and not leap: return 'Shushan Purim' elif month == 13: if day == 14: return 'Purim' elif day == 15: return 'Shushan Purim' elif month == 1 and day in range(15, 22 if israel else 23): return 'Pesach' elif month == 2 and day == 18: return "Lag Ba'omer" elif month == 3 and (day == 6 if israel else day in (6, 7)): return 'Shavuos' elif month == 5 and day == 15: return "Tu B'av" class Year(object): """ A Year object represents a Hebrew calendar year. It provided the following operators: ===================== ================================================ Operation Result ===================== ================================================ year2 = year1 + int New ``Year`` ``int`` days after year1. year2 = year1 - int New ``Year`` ``int`` days before year1. int = year1 - year2 ``int`` equal to the absolute value of the difference between year2 and year1. bool = year1 == year2 True if year1 represents the same year as year2. ===================== ================================================ Parameters ---------- year : int A Hebrew year. Attributes ---------- year : int The hebrew year. leap : bool True if the year is a leap year else false. """ def __init__(self, year): """ The initializer for a Year object. """ if year < 1: raise ValueError('Year {0} is before creation.'.format(year)) self.year = year self.leap = HebrewDate._is_leap(year) def __repr__(self): return 'Year({0})'.format(self.year) def __len__(self): return HebrewDate._days_in_year(self.year) def __eq__(self, other): if isinstance(other, Year) and self.year == other.year: return True return False def __add__(self, other): """Add int to year.""" return Year(self.year + other) def __sub__(self, other): """Subtract int or Year from Year. If other is an int return a new Year other before original year. If other is a Year object, return delta of the two years as an int. """ if isinstance(other, Year): return abs(self.year - other.year) else: try: return Year(self.year - other) except AttributeError: raise TypeError('Only an int or another Year object can' ' be subtracted from a year.') def __iter__(self): """Yield integer for each month in year.""" months = [7, 8, 9, 10, 11, 12, 13, 1, 2, 3, 4, 5, 6] if not self.leap: months.remove(13) for month in months: yield month def itermonths(self): """Yield Month instance for each month of the year. Yields ------ Month The next month in the Hebrew calendar year as a ``luachcal.hebrewcal.Month`` instance beginning with Tishrei and ending with Elul. """ for month in self: yield Month(self.year, month) def iterdays(self): """Yield integer for each day of the year. Yields ------ int An integer beginning with 1 representing the next day of the year. """ for day in range(1, len(self) + 1): yield day def iterdates(self): """Yield HebrewDate instance for each day of the year. Yields ------ ``HebrewDate`` The next date of the Hebrew calendar year starting with the first of Tishrei. """ for month in self.itermonths(): for day in month: yield HebrewDate(self.year, month.month, day) class Month(object): """ A Month object represents a month of the Hebrew calendar. Parameters ---------- year : int month : int The month as an integer starting with 7 for Tishrei through 13 if necessary for Adar Sheni and then 1-6 for Nissan - Elul. Attributes ---------- year : int The Hebrew year. month : int The month as an integer starting with 7 for Tishrei through 13 if necessary for Adar Sheni and then 1-6 for Nissan - Elul. name : str The name of the month. """ _monthnames = {7: 'Tishrei', 8: 'Cheshvan', 9: 'Kislev', 10: 'Teves', 11: 'Shvat', 13:'Adar Sheni', 1: 'Nissan', 2: 'Iyar', 3: 'Sivan', 4: 'Tamuz', 5: 'Av', 6: 'Elul'} def __init__(self, year, month): if year < 1: raise ValueError('Year is before creation.') self.year = year leap = HebrewDate._is_leap(self.year) yearlength = 13 if leap else 12 if month < 1 or month > yearlength: raise ValueError('''Month must be between 1 and 12 for a normal year and 13 for a leap year.''') self.month = month self._monthnames[12] = 'Adar Rishon' if leap else 'Adar' self.name = self._monthnames[self.month] def __repr__(self): return 'Month({0}, {1})'.format(self.year, self.month) def __len__(self): return HebrewDate._month_length(self.year, self.month) def __iter__(self): for day in range(1, len(self) + 1): yield day def __eq__(self, other): if( isinstance(other, Month) and self.year == other.year and self.month == other.month): return True return False def __add__(self, other): yearmonths = list(Year(self.year)) index = yearmonths.index(self.month) leftover_months = len(yearmonths[index + 1:]) if other <= leftover_months: return Month(self.year, yearmonths[index + other]) return Month(self.year + 1, 7).__add__(other - 1 - leftover_months) def __sub__(self, other): if isinstance(other, Number): yearmonths = list(Year(self.year)) index = yearmonths.index(self.month) leftover_months = index if other <= leftover_months: return Month(self.year, yearmonths[index - other]) return Month(self.year - 1, deque(Year(self.year - 1), maxlen=1).pop()).__sub__( other - 1 - leftover_months ) # Recursive call on the last month of the previous year. try: return abs(self._elapsed_months() - other._elapsed_months()) except AttributeError: raise TypeError('''You can only subtract a number or a month object from a month''') def starting_weekday(self): """Return first weekday of the month. Returns ------- int The weekday of the first day of the month starting with Sunday as 1 through Saturday as 7. """ return HebrewDate(self.year, self.month, 1).weekday() def _elapsed_months(self): '''Return number of months elapsed from beginning of calendar''' yearmonths = tuple(Year(self.year)) months_elapsed = ( (235 * ((self.year-1) // 19)) + (12 * ((self.year-1) % 19)) + (7 * ((self.year-1) % 19) + 1) // 19 + yearmonths.index(self.month) ) return months_elapsed def iterdates(self): """Return iterator that yields an instance of HebrewDate. Yields ------ ``HebrewDate`` The next Hebrew Date of the year starting the first day of Tishrei through the last day of Ellul. """ for day in self: yield HebrewDate(self.year, self.month, day) pyluach-1.0.1/pyluach/parshios.py000066400000000000000000000141371343663022700170410ustar00rootroot00000000000000"""This module has functions to find the weekly parasha for a given Shabbos. Attributes ---------- PARSHIOS : list of str A list of all of the parsha names starting with Beraishis through V'zos Habrocha. Notes ----- The algorithm is based on Dr. Irv Bromberg's, University of Toronto at http://individual.utoronto.ca/kalendis/hebrew/parshah.htm All parsha names are transliterated into the American Ashkenazik pronunciation. """ from __future__ import division from __future__ import unicode_literals from collections import deque, OrderedDict from pyluach.dates import HebrewDate from pyluach.utils import memoize PARSHIOS = [ 'Beraishis', 'Noach', "Lech L'cha", 'Vayera', 'Chayei Sarah', 'Toldos', 'Vayetzei', 'Vayishlach', 'Vayeshev', 'Miketz', 'Vayigash', 'Vayechi', 'Shemos', "Va'era", 'Bo', 'Beshalach', 'Yisro', 'Mishpatim', 'Teruma', 'Tetzave', 'Ki Sisa', 'Vayakhel', 'Pekudei', 'Vayikra', 'Tzav','Shemini', 'Tazria', 'Metzora', 'Acharei Mos', 'Kedoshim', 'Emor', 'Behar', 'Bechukosai', 'Bamidbar', 'Naso', "Beha'aloscha", "Shelach", 'Korach', 'Chukas', 'Balak', 'Pinchas', 'Matos', "Ma'sei", 'Devarim', "Va'eschanan", 'Eikev', "R'ey", 'Shoftim', 'Ki Setzei', 'Ki Savo', 'Netzavim', 'Vayelech', 'Haazinu', "V'zos Habrocha" ] def _parshaless(date, israel=False): if israel and date.tuple()[1:] in [(7,23), (1,22), (3,7)]: return False if date.month == 7 and date.day in ([1,2,10] + list(range(15, 24))): return True if date.month == 1 and date.day in range(15, 23): return True if date.month == 3 and date.day in [6, 7]: return True return False @memoize(maxlen=50) def _gentable(year, israel=False): """Return OrderedDict mapping date of Shabbos to list of parsha numbers. The numbers start with Beraishis as 0. Double parshios are represented as a list of the two numbers. If there is no Parsha the value is None. """ parshalist = deque([51, 52] + list(range(52))) table = OrderedDict() leap = HebrewDate._is_leap(year) pesachday = HebrewDate(year, 1, 15).weekday() rosh_hashana = HebrewDate(year, 7, 1) shabbos = (rosh_hashana + 2).shabbos() if rosh_hashana.weekday() > 4: parshalist.popleft() while shabbos.year == year: if _parshaless(shabbos, israel): table[shabbos] = None else: parsha = parshalist.popleft() table[shabbos] = [parsha,] if( (parsha == 21 and (HebrewDate(year, 1, 14)-shabbos) // 7 < 3) or (parsha in [26, 28] and not leap) or (parsha == 31 and not leap and ( not israel or pesachday != 7 )) or (parsha == 38 and not israel and pesachday == 5) or (parsha == 41 and (HebrewDate(year, 5, 9)-shabbos) // 7 < 2) or (parsha == 50 and HebrewDate(year+1, 7, 1).weekday() > 4) ): # If any of that then it's a double parsha. table[shabbos].append(parshalist.popleft()) shabbos += 7 return table def getparsha(date, israel=False): """Return the parsha for a given date. Returns the parsha for the Shabbos on or following the given date. Parameters ---------- date : ``HebrewDate``, ``GregorianDate``, or ``JulianDay`` This date does not have to be a Shabbos. israel : bool, optional ``True`` if you want the parsha according to the Israel schedule (with only one day of Yom Tov). Defaults to ``False``. Returns ------- list of ints or ``None`` A list of the numbers of the parshios for the Shabbos of the given date, beginning with 0 for Beraishis, or ``None`` if the Shabbos doesn't have a parsha (i.e. it's on Yom Tov). """ shabbos = date.to_heb().shabbos() table = _gentable(shabbos.year, israel) return table[shabbos] def getparsha_string(date, israel=False): """Return the parsha as a string for the given date. This function wraps ``getparsha`` returning a the parsha name transliterated into English. Parameters ---------- date : ``HebrewDate``, ``GregorianDate``, or ``JulianDay`` This date does not have to be a Shabbos. israel : bool, optional ``True`` if you want the parsha according to the Israel schedule (with only one day of Yom Tov). Defaults to ``False``. Returns ------- str or ``None`` The name of the parsha seperated by a comma and space if it is a double parsha or ``None`` if there is no parsha that Shabbos (ie. it's yom tov). """ parsha = getparsha(date, israel) if parsha is None: return None name = [PARSHIOS[n] for n in parsha] return ', '.join(name) def iterparshios(year, israel=False): """Generate all the parshios in the year. Parameters ---------- year : int The Hebrew year to get the parshios for. israel : bool, optional ``True`` if you want the parsha according to the Israel schedule (with only one day of Yom Tov). Defaults to ``False`` Yields ------ list of ints or ``None`` A list of the numbers of the parshios for the next Shabbos in the given year. Yields ``None`` for a Shabbos that doesn't have its own parsha (i.e. it occurs on a yom tov). """ table = _gentable(year, israel) for shabbos in table: yield table[shabbos] def parshatable(year, israel=False): """Return a table of all the Shabbosos in the year Parameters ---------- year : int The Hebrew year to get the parshios for. israel : bool, optional ``True`` if you want the parshios according to the Israel schedule (with only one day of Yom Tov). Defaults to ``False``. Returns ------- OrderedDict An ordered dictionary with the date of each Shabbos as the key mapped to the parsha as a list of ints, or ``None`` for a Shabbos with no parsha. """ return _gentable(year, israel) pyluach-1.0.1/pyluach/utils.py000066400000000000000000000027551343663022700163540ustar00rootroot00000000000000from collections import OrderedDict class Cache(OrderedDict): """Extends OrderdDict. Accepts an extra kwarg maxlength which sets the maximum length of the dictionary. If you add more than the maxlength it deletes entries oldest first by extending __setitem__. """ def __init__(self, *args, **kwargs): self.maxlen = kwargs.pop('maxlen', None) super(Cache, self).__init__(*args, **kwargs) def __setitem__(self, key, value): if self.maxlen is not None: while len(self) >= self.maxlen: self.popitem(False) OrderedDict.__setitem__(self, key, value) class memoize(object): """Memoize the result of a function. This class is used as a decorator to remember the return value of a function or method for multiple calls based on the arguments. For class or static methods this decorator should come after the classmethod or staticmethod decorator, and it should go without saying that it will not work as expected if used on a method that depends on the current state of the object. Also all arguments to the function it is used on must be hashable. """ def __init__(self, maxlen=None): self.cache = Cache(maxlen=maxlen) def __call__(self, func): def innercall(*args): if args in self.cache: return self.cache[args] result = func(*args) self.cache[args] = result return result return innercall pyluach-1.0.1/setup.py000066400000000000000000000017561343663022700147070ustar00rootroot00000000000000from setuptools import setup import io setup(name='pyluach', version='1.0.1', author='MS List', author_email='simlist@gmail.com', packages=['pyluach', ], url='https://github.com/simlist/pyluach', license='MIT', description=("""Pyluach is a Python package for manipulating Hebrew dates, Gregorian-Hebrew calendar conversions, and other Jewish calendar related calculations."""), long_description=io.open('README.rst').read(), classifiers=['Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', 'License :: OSI Approved :: MIT License', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3'], keywords=['hebrew', 'calendar', 'jewish', 'luach', 'gregorian', 'julian', 'days', 'dates', 'date', 'conversion', 'parsha', 'holiday'] ) pyluach-1.0.1/tests/000077500000000000000000000000001343663022700143265ustar00rootroot00000000000000pyluach-1.0.1/tests/__init__.py000066400000000000000000000000001343663022700164250ustar00rootroot00000000000000pyluach-1.0.1/tests/test_dates.py000066400000000000000000000170771343663022700170530ustar00rootroot00000000000000import pytest from operator import gt, lt, eq, ne, ge, le, add, sub import datetime from pyluach import dates from pyluach.dates import HebrewDate, GregorianDate, JulianDay KNOWN_VALUES = {(2009, 8, 21): (5769, 6, 1), (2009, 9, 30): (5770, 7, 12), (2009, 11, 13): (5770, 8, 26), (2010, 1, 21): (5770, 11, 6), (2010, 5, 26): (5770, 3, 13), (2013, 11, 17): (5774, 9, 14), (2014, 3, 12): (5774, 13, 10), (2014, 6, 10): (5774, 3, 12), (2016, 2, 10): (5776, 12, 1) } @pytest.fixture(scope='module') def datetypeslist(): datetypes = [dates.HebrewDate, dates.GregorianDate] return datetypes class TestClassesSanity(object): def test_greg_sanity(self): for i in range(347998, 2460000, 117): jd = dates.JulianDay(i) conf = jd.to_greg().to_jd() if jd >= dates.GregorianDate(1, 1, 1): assert jd.day == conf.day else: assert abs(jd.day - conf.day) <= 1 def test_heb_sanity(self): for i in range(347998, 2460000, 117): jd = dates.JulianDay(i) conf = jd.to_heb().to_jd() assert jd.day == conf.day class TestClassesConversion(object): def test_from_greg(self): for date in KNOWN_VALUES: heb = dates.GregorianDate(*date).to_heb().tuple() assert KNOWN_VALUES[date] == heb def test_from_heb(self): for date in KNOWN_VALUES: greg = dates.HebrewDate(*KNOWN_VALUES[date]).to_greg().tuple() assert date == greg @pytest.fixture def setup(scope='module'): caltypes = [GregorianDate, HebrewDate, JulianDay] deltas = [0, 1, 29, 73, 1004] return {'caltypes': caltypes, 'deltas': deltas} class TestOperators(object): def test_add(self, setup): for cal in setup['caltypes']: for delta in setup['deltas']: date = cal.today() date2 = date + delta assert date.jd + delta == date2.jd def test_min_int(self, setup): '''Test subtracting a number from a date''' for cal in setup['caltypes']: for delta in setup['deltas']: date = cal.today() date2 = date - delta assert date.jd - delta == date2.jd def test_min_date(self, setup): '''Test subtracting one date from another This test loops through subtracting the current date of each calendar from a date of each calendar at intervals from the current date. ''' for cal in setup['caltypes']: for cal2 in setup['caltypes']: for delta in setup['deltas']: today = cal.today() difference = (cal2.today() - delta) - today assert delta == difference class TestComparisons(object): """In ComparisonTests, comparisons are tested. Every function tests one test case comparing a date from each calendar type to another date from each calendar type. """ def test_gt(self, setup): """Test all comparers when one date is greater.""" for cal in setup['caltypes']: today = cal.today() for cal2 in setup['caltypes']: yesterday = cal2.today() - 1 for comp in [gt, ge, ne]: assert comp(today, yesterday) for comp in [eq, lt, le]: assert comp(today, yesterday) is False def test_lt(self, setup): """Test all comparers when one date is less than another.""" for cal in setup['caltypes']: today = cal.today() for cal2 in setup['caltypes']: tomorrow = cal2.today() + 1 for comp in [lt, le, ne]: assert comp(today, tomorrow) for comp in [gt, ge, eq]: assert comp(today, tomorrow) is False def test_eq(self, setup): """Test all comparers when the dates are equal.""" for cal in setup['caltypes']: today = cal.today() for cal2 in setup['caltypes']: today2 = cal2.today() for comp in [eq, ge, le]: assert comp(today, today2) for comp in [gt, lt, ne]: assert comp(today, today2) is False class TestErrors(object): def test_too_low_heb(self): with pytest.raises(ValueError): dates.HebrewDate(0, 7, 1) with pytest.raises(ValueError): dates.HebrewDate(-1, 7, 1) def test_comparer_errors(self): day1 = dates.HebrewDate(5777, 12, 10) for date in [day1, day1.to_greg(), day1.to_jd()]: for comparer in [gt, lt, eq, ne, ge, le]: for value in [1, 0, 'hello', None, '']: with pytest.raises(TypeError): comparer(date, value) def test_operator_errors(self): day = dates.GregorianDate(2016, 11, 20) for operator in [add, sub]: for value in ['Hello', '', None]: with pytest.raises(TypeError): operator(day, value) with pytest.raises(TypeError): day + (day+1) def test_HebrewDate_errors(self): with pytest.raises(ValueError): HebrewDate(0, 6, 29) for datetuple in [(5778, 0, 5), (5779, -1, 7), (5759, 14, 8), (5778, 13, 20)]: with pytest.raises(ValueError): HebrewDate(*datetuple) for datetuple in [(5778, 6, 0), (5779, 8, 31), (5779, 10, 30)]: with pytest.raises(ValueError): HebrewDate(*datetuple) def test_GregorianDate_errors(self): for datetuple in [(2018, 0, 3), (2018, -2, 8), (2018, 13, 9), (2018, 2, 0), (2018, 2, 29), (2012, 2, 30)]: with pytest.raises(ValueError): GregorianDate(*datetuple) class TestReprandStr(object): def test_repr(self, datetypeslist): for datetype in datetypeslist: assert eval(repr(datetype.today())) == datetype.today() jd = JulianDay.today() assert eval(repr(jd)) == jd def test_jd_str(self): assert str(JulianDay(550.5)) == '550.5' assert str(JulianDay(1008)) == '1007.5' def test_greg_str(self): date = GregorianDate(2018, 8, 22) assert str(date) == '2018-08-22' assert str(GregorianDate(2008, 12, 2)) == '2008-12-02' assert str(GregorianDate(1, 1, 1)) == '0001-01-01' def test_weekday(): assert GregorianDate(2017, 8, 7).weekday() == 2 assert HebrewDate(5777, 6, 1).weekday() == 4 assert JulianDay(2458342.5).weekday() == 1 class TestMixinMethods(): @pytest.fixture def date(self): return dates.GregorianDate(2017, 10, 31) def test_str(self, date): assert str(date) == '2017-10-31' def test_dict(self, date): assert date.dict() == {'year': 2017, 'month': 10, 'day': 31} def test_iter(self, date): assert list(date) == [date.year, date.month, date.day] def test_to_pydate(): day = HebrewDate(5778, 6, 1) jd = day.to_jd() for day_type in [day, jd]: assert day_type.to_pydate() == datetime.date(2018, 8, 12) def test_from_pydate(): date = datetime.date(2018, 8, 27) assert date == GregorianDate.from_pydate(date).to_jd().to_pydate() assert date == HebrewDate.from_pydate(date).to_pydate() assert date == JulianDay.from_pydate(date).to_pydate() pyluach-1.0.1/tests/test_hebrewcal.py000066400000000000000000000151731343663022700177020ustar00rootroot00000000000000from pyluach import dates, hebrewcal from pyluach.hebrewcal import Year, Month, holiday class TestYear(object): def test_repryear(self): year = Year(5777) assert eval(repr(year)) == year def test_iteryear(self): assert list(Year(5777)) == [7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6] assert list(Year(5776)) == [7, 8, 9, 10, 11, 12, 13, 1, 2, 3, 4, 5, 6] def test_equalyear(self): year1 = hebrewcal.Year(5777) year2 = hebrewcal.Year(5777) assert year1 == year2 def test_addtoyear(self): year = Year(5777) assert year + 2 == Year(5779) assert year + 0 == year def test_subtractintfromyear(self): year = Year(5777) assert year - 0 == year assert year - 3 == Year(5774) def test_subtractyearfromyear(self): year = Year(5777) assert year - year == 0 assert year - (year - 1) == 1 assert year - (year + 2) == 2 def test_iterdays(self): year = Year(5778) yearlist = list(year.iterdays()) assert len(yearlist) == len(year) assert yearlist[0] == 1 assert yearlist[-1] == len(year) def test_iterdates(self): year = 5778 workingdate = dates.HebrewDate(year, 7, 1) for date in Year(year).iterdates(): assert workingdate == date workingdate += 1 class TestMonth(object): def test_reprmonth(self): month = Month(5777, 10) assert eval(repr(month)) == month def test_equalmonth(self): month1 = hebrewcal.Month(5777, 12) month2 = hebrewcal.Month(5777, 12) assert month1 == month2 assert not month1 == (month2 + 1) def test_addinttomonth(self): month = hebrewcal.Month(5777, 12) assert month + 0 == month assert month + 1 == hebrewcal.Month(5777, 1) assert month + 6 == hebrewcal.Month(5777, 6) assert month + 7 == hebrewcal.Month(5778, 7) assert month + 35 == hebrewcal.Month(5780, 10) def test_subtract_month(self): month1 = hebrewcal.Month(5775, 10) month2 = hebrewcal.Month(5776, 10) month3 = hebrewcal.Month(5777, 10) assert month1 - month2 == 12 assert month3 - month1 == 25 def test_subtractintfrommonth(self): month = hebrewcal.Month(5778, 9) assert month - 2 == hebrewcal.Month(5778, 7) assert month - 3 == hebrewcal.Month(5777, 6) assert month - 30 == hebrewcal.Month(5775, 4) def test_startingweekday(self): assert Month(5778, 8).starting_weekday() == 7 assert Month(5778, 9).starting_weekday() == 1 def test_iterdate(self): year = 5770 workingdate = dates.HebrewDate(year, 7 ,1) for month in (list(range(7, 13)) + list(range(1, 7))): for date in Month(year, month).iterdates(): assert date == workingdate workingdate += 1 class TestHoliday(object): def test_roshhashana(self): roshhashana = dates.HebrewDate(5779, 7, 1) assert all([holiday(day, location) == 'Rosh Hashana' for day in[roshhashana, roshhashana + 1] for location in [True, False] ]) def test_yomkippur(self): assert holiday(dates.HebrewDate(5775, 7, 10)) == 'Yom Kippur' def test_succos(self): day = dates.HebrewDate(5778, 7, 18) assert holiday(day) == 'Succos' day2 = dates.HebrewDate(5778, 7, 23) assert holiday(day2, israel=True) is None def test_shmini(self): shmini = dates.HebrewDate(5780, 7, 22) assert holiday(shmini, True) == 'Shmini Atzeres' assert holiday(shmini) == 'Shmini Atzeres' assert holiday(shmini + 1) == 'Simchas Torah' assert holiday(shmini + 1, True) is None def test_chanuka(self): chanuka = dates.HebrewDate(5778, 9, 25) for i in range(8): assert holiday(chanuka + i) == 'Chanuka' def test_tubshvat(self): assert holiday(dates.HebrewDate(5779, 11, 15)) == "Tu B'shvat" def test_purim(self): purims = [dates.HebrewDate(5778, 12, 14), dates.HebrewDate(5779, 13, 14)] for purim in purims: assert holiday(purim) == 'Purim' assert holiday(purim + 1) == 'Shushan Purim' assert holiday(dates.HebrewDate(5779, 12, 14)) == 'Purim Katan' def test_pesach(self): pesach = dates.HebrewDate(5778, 1, 15) for i in range (6): assert ( holiday(pesach + i, True) == 'Pesach' and holiday(pesach + i) == 'Pesach' ) eighth = pesach + 7 assert holiday(eighth) == 'Pesach' and holiday(eighth, True) is None assert holiday(eighth + 1) is None def test_lagbaomer(self): assert holiday(dates.GregorianDate(2018, 5, 3)) == "Lag Ba'omer" def test_shavuos(self): shavuos = dates.HebrewDate(5778, 3, 6) assert all([holiday(day) == 'Shavuos' for day in [shavuos, shavuos + 1]]) assert holiday(shavuos, True) == 'Shavuos' assert holiday(shavuos + 1, True) is None def test_tubeav(self): assert holiday(dates.HebrewDate(5779, 5, 15)) == "Tu B'av" class TestFasts(object): def test_gedalia(self): assert holiday(dates.HebrewDate(5779, 7, 3)) == 'Tzom Gedalia' assert holiday(dates.HebrewDate(5778, 7, 3)) is None assert holiday(dates.HebrewDate(5778, 7, 4)) == 'Tzom Gedalia' def test_asara(self): assert holiday(dates.GregorianDate(2018, 12, 18)) == '10 of Teves' def test_esther(self): fasts = [ dates.HebrewDate(5778, 12, 13), dates.HebrewDate(5776, 13, 13), dates.HebrewDate(5777, 12, 11), #nidche dates.HebrewDate(5784, 13, 11) #ibbur and nidche ] for fast in fasts: assert holiday(fast) == 'Taanis Esther' non_fasts = [ dates.HebrewDate(5776, 12, 13), dates.HebrewDate(5777, 12, 13), dates.HebrewDate(5784, 12, 11), dates.HebrewDate(5784, 13, 13) ] for non in non_fasts: assert holiday(non) is None def test_tamuz(self): fasts = [dates.HebrewDate(5777, 4, 17), dates.HebrewDate(5778, 4, 18)] for fast in fasts: assert holiday(fast) == '17 of Tamuz' assert holiday(dates.HebrewDate(5778, 4, 17)) is None def test_av(self): fasts = [dates.HebrewDate(5777, 5, 9), dates.HebrewDate(5778, 5, 10)] for fast in fasts: assert holiday(fast) == '9 of Av' assert holiday(dates.HebrewDate(5778, 5, 9)) is None pyluach-1.0.1/tests/test_parshios.py000066400000000000000000000044151343663022700175730ustar00rootroot00000000000000import pytest from pyluach import parshios, dates KNOWN_VALUES = { (2016, 1, 7): [13,], (2017, 3, 21): [21, 22], (2017, 9, 26): None } KNOWN_VALUES_STRINGS = { (2016, 1, 7): "Va'era", (2017, 3, 21): "Vayakhel, Pekudei", (2017, 9, 26): None } class TestGetParsha(object): def test_getparsha(self): for key in KNOWN_VALUES: assert (parshios.getparsha(dates.GregorianDate(*key)) == KNOWN_VALUES[key]) def test_getparsha_string(self): for key in KNOWN_VALUES_STRINGS: assert (parshios.getparsha_string(dates.GregorianDate(*key)) == KNOWN_VALUES_STRINGS[key]) def test_chukas_balak(self): chukas_balak = dates.HebrewDate(5780, 4, 12) assert parshios.getparsha(chukas_balak) == [38, 39] assert parshios.getparsha(chukas_balak, True) == [39, ] assert parshios.getparsha(chukas_balak - 8) == [37, ] assert parshios.getparsha(chukas_balak - 13, True) == [38, ] shavuos = dates.HebrewDate(5780, 3, 6) assert parshios.getparsha_string(shavuos, True) == 'Naso' assert parshios.getparsha_string(shavuos) is None assert parshios. getparsha_string(shavuos + 7, True) == "Beha'aloscha" assert parshios.getparsha_string(shavuos + 7) == 'Naso' def test_eighth_day_pesach(self): eighth_day_pesach = dates.HebrewDate(5779, 1, 22) reunion_shabbos = dates.HebrewDate(5779, 5, 2) assert parshios.getparsha_string(eighth_day_pesach) is None assert parshios.getparsha_string(eighth_day_pesach, True) == 'Acharei Mos' assert parshios.getparsha(eighth_day_pesach + 7) == [28,] assert parshios.getparsha(eighth_day_pesach + 7, True) == [29,] assert parshios.getparsha_string(reunion_shabbos) == "Matos, Ma'sei" assert parshios.getparsha_string(reunion_shabbos, True) == "Ma'sei" def test_parshatable(): assert parshios.parshatable(5777) == parshios._gentable(5777) assert parshios.parshatable(5778, True) == parshios._gentable(5778, True) def test_iterparshios(): year = 5776 parshalist = list(parshios.parshatable(year).values()) index = 0 for p in parshios.iterparshios(year): assert p == parshalist[index] index += 1