PK{G@-ddscal/__init__.py#!/usr/bin/env python3 # Copyright Louis Paternault 2013-2015 # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . 1 """Calendar producer""" VERSION = "0.3.0" __AUTHOR__ = "Louis Paternault (spalax@gresille.org)" __COPYRIGHT__ = "(C) 2011-2015 Louis Paternault. GNU GPL 3 or later." PKYFe^ِscal/__main__.py#!/usr/bin/env python3 # Copyright Louis Paternault 2011-2015 # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . 1 """Produce a calendar.""" import logging import sys from scal import calendar, errors, options from scal.template import generate_tex import scal LOGGER = logging.getLogger(scal.__name__) LOGGER.addHandler(logging.StreamHandler()) def main(): """Main function""" arguments = options.commandline_parser().parse_args(sys.argv[1:]) try: inputcalendar = calendar.Calendar(arguments.FILE[0]) except errors.ConfigError as error: LOGGER.error("Configuration error in file {}: {}".format( arguments.FILE[0].name, error, )) sys.exit(1) print(generate_tex(inputcalendar, arguments.template, arguments.weeks)) if __name__ == "__main__": main() PK[F!0!0scal/calendar.py#!/usr/bin/env python3 # Copyright Louis Paternault 2011-2015 # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . 1 """Configuration file and its representation.""" import datetime import logging import re from scal import errors LOGGER = logging.getLogger(__name__) WEEK_CHOICES = ['both', 'none', 'work', 'iso'] def parse_weeks(text): """Convert text into the inner representation of week option.""" if text not in WEEK_CHOICES: raise KeyError(text) return { 'work': text in ['both', 'work'], 'iso': text in ['both', 'iso'], } def is_between(start, middle, end): """Return True if `middle` is between `start` and `end`.""" return start <= middle and middle <= end class Period: """A (possibly named) period of time""" #pylint: disable=too-few-public-methods start = None end = None name = None def __init__(self, start, end, name=None): if start > end: raise errors.ConfigError("Start date is older than end date.") self.start = start self.end = end self.name = name def __str__(self): txt = "{} --- {}".format(self.start, self.end) if self.name: return "{}: {}".format(txt, self.name) else: return txt def is_in(self, day): """Return True iff ``day`` is in this period.""" return is_between(self.start, day, self.end) RE_DATE_STR = r'((?P\d{{4}})-)?(?P\d{{2}})-(?P\d{{2}})' #pylint: disable=line-too-long RE_DATE = re.compile(RE_DATE_STR.format(id="")) RE_FROMTO = re.compile(r'^From *{} *to *{}$'.format( RE_DATE_STR.format(id='0'), RE_DATE_STR.format(id='1'), )) RE_HOLIDAY = re.compile(r'^(?P{})? *(?P{}) *(?P.*)$'.format( RE_DATE_STR.format(id='0'), RE_DATE_STR.format(id='1'), )) RE_AFFECTATION = re.compile(r'^(?P\w*) *= *(?P.*)$') DEFAULT_CONFIG = { 'lang': 'english', 'papersize': 'a4paper', } WEDNESDAY = 3 def date(year, month, day): """Return a `datetime.date` object. The arguments may be anything that can be converted to integers. """ return datetime.date(int(year), int(month), int(day)) def last_day_of_month(mydate): "Return a date corresponding to the last day of the month of the argument." if mydate.month == 12: next_month = mydate.replace(mydate.year + 1, 1, 1) else: next_month = mydate.replace(mydate.year, mydate.month + 1, 1) return next_month - datetime.timedelta(days=1) def weeknumber(day): """Return week number.""" return day.isocalendar()[1] class Calendar: """A calendar, that is, a start date, an end date, and holidays.""" def __init__(self, file): self.start = None self.end = None self.holidays = [] self.config = DEFAULT_CONFIG.copy() linenumber = 0 for line in file: linenumber += 1 stripped = line.split("#")[0].strip(' \n') if not stripped: continue if RE_FROMTO.match(stripped): match = RE_FROMTO.match(stripped) self.set_start( match.group('year0'), match.group('month0'), match.group('day0'), ) self.set_end( match.group('year1'), match.group('month1'), match.group('day1') ) elif RE_HOLIDAY.match(stripped): match = RE_HOLIDAY.match(stripped) self.add_holiday( ( match.group('year0'), match.group('month0'), match.group('day0'), ), ( match.group('year1'), match.group('month1'), match.group('day1'), ), match.group('name'), line ) elif RE_AFFECTATION.match(stripped): match = RE_AFFECTATION.match(stripped) self.config[match.group('name')] = match.group('value') else: raise errors.ConfigError( "Could not parse line {}: '{}'.".format( linenumber, line[:-1], ) ) if self.start is None or self.end is None: raise errors.ConfigError("Missing start or end date.") # Filling first and last month if self.start.day != 1: self.holidays.append(Period( datetime.date(self.start.year, self.start.month, 1), self.start - datetime.timedelta(days=1), )) self.start = datetime.date(self.start.year, self.start.month, 1) if self.end != last_day_of_month(self.end): self.holidays.append(Period( self.end + datetime.timedelta(days=1), last_day_of_month(self.end), )) self.end = last_day_of_month(self.end) def set_start(self, year, month, day): """Defin the start date of the calendar.""" if self.start is not None: raise errors.ConfigError( "Calendar boundaries configured twice." ) if year is None: raise errors.ConfigError( "Missing year in 'From to ' line." ) self.start = date(year, month, day) def set_end(self, year, month, day): """Defin the end date of the calendar.""" if self.end is not None: raise errors.ConfigError( "Calendar boundaries configured twice." ) if year is None: raise errors.ConfigError( "Missing year in 'From to ' line." ) self.end = date(year, month, day) def add_holiday(self, date0, date1, name="", line=None): """Add a holiday, starting on `date0` and ending on `date1`. This holiday may be named. If it is read from the configuration file, the content of the corresponding line may be provided. """ year0, month0, day0 = date0 year1, month1, day1 = date1 if (year0 is None) and (month0 is None) and (day0 is None): year0, month0, day0 = year1, month1, day1 if ( (year0 is None) and (year1 is not None) ) or ( (year0 is not None) and (year1 is None) ): raise errors.ConfigError( "Either one or both years may be omitted (line '{}').".format( str(line) ) ) if year0 is None: for year in range(self.start.year, self.end.year + 1): try: if ( is_between( self.start, date(year, month0, day0), self.end, ) and is_between( self.start, date(year, month1, day1), self.end, ) ): self.holidays.append(Period( date(year, month0, day0), date(year, month1, day1), name, )) except errors.ConfigError: LOGGER.warning( ( "Ignored period {}--{} (invalid or outside " "calendar boundaries)." ).format( date(year, month0, day0), date(year, month1, day1) ) ) else: try: self.holidays.append(Period( date(year0, month0, day0), date(year1, month1, day1), name, )) except errors.ConfigError: LOGGER.warning( ( "Ignored period {}--{} (invalid or outside calendar " "boundaries)." ).format( date(year0, month0, day0), date(year1, month1, day1), ) ) def is_holiday(self, day): """Return True iff ``day`` is in a holiday.""" return len([ None for holiday in self.holidays if holiday.is_in(day) ]) > 0 def months_count(self): """Return the number of months of the calendar.""" return ( 12 * (self.end.year - self.start.year) + self.end.month - self.start.month + 1 ) def year_boundaries(self): """Return the first and last month of each year, as a dictionary. This is important for the first and last years, which can start or end by something else than January or December. """ years = {} for year in range(self.start.year, self.end.year + 1): if self.start.year == self.end.year: boundaries = [self.start.month, self.end.month] elif year == self.start.year: boundaries = [self.start.month, 12] elif year == self.end.year: boundaries = [1, self.end.month] else: boundaries = [1, 12] years[year] = [format(i, '02d') for i in boundaries] return years def is_workingweek(self, wednesday): """Return True iff week of argument is a working week.""" all_holiday = True for day in range(wednesday.toordinal() - 2, wednesday.toordinal() + 3): all_holiday = ( all_holiday and self.is_holiday(datetime.date.fromordinal(day)) ) return not all_holiday def week_iterator(self): """Iterate over weeks of self.""" # Looking for first wednesday for day in range(self.start.toordinal(), self.start.toordinal()+7): if datetime.date.fromordinal(day).isoweekday() == WEDNESDAY: wednesday = datetime.date.fromordinal(day) workweek = 0 while wednesday <= self.end: if self.is_workingweek(wednesday): workweek += 1 maybe_workweek = workweek else: maybe_workweek = None yield wednesday, maybe_workweek, weeknumber(wednesday) wednesday += datetime.timedelta(days=7) def weeks(self, work, iso): """Return the list of weeks, processed by template.""" weeks = [] for (day, work_number, iso_number) in self.week_iterator(): week = { 'date': day, 'work': None, 'iso': None, } if work: week['work'] = work_number if iso: week['iso'] = iso_number weeks.append(week) return weeks def __str__(self): return ( "From {} to {}\n".format(self.start, self.end) + "\n".join([str(holiday) for holiday in self.holidays]) ) PKHE%sscal/errors.py#!/usr/bin/env python3 # Copyright Louis Paternault 2011-2014 # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . 1 """Errors and exceptions""" class ScalError(Exception): """Generic error for scal""" pass class ConfigError(ScalError): """Error in configuration file.""" def __init__(self, message=""): super().__init__() self.message = message def __str__(self): return self.message PK7TG%*^ ^ scal/options.py#!/usr/bin/env python3 # Copyright Louis Paternault 2011-2015 # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . 1 """Command line options""" import argparse import os import textwrap import sys from scal import VERSION from scal import calendar def _type_week(text): """Check that --week argument is of the right type.""" try: return calendar.parse_weeks(text) except KeyError: raise argparse.ArgumentTypeError( "argument must be one of {{{}}}.".format( ", ".join(calendar.WEEK_CHOICES) ) ) def _file_exists(text): """Check that file exists.""" if os.path.exists(text): return text else: raise argparse.ArgumentTypeError( "'{}' must be an existing file.".format(text) ) def commandline_parser(): """Return a command line parser.""" parser = argparse.ArgumentParser( prog="scal", description="A year calendar producer.", ) parser.add_argument( '--version', help='Show version', action='version', version='%(prog)s ' + VERSION ) parser.add_argument( '--weeks', '-w', help=textwrap.dedent(""" Display week numbers : ISO week numbers, number of worked weeks since the beginning, or both. """), type=_type_week, default='both', ) parser.add_argument( '--template', '-t', help='Template to use, if different from default template', type=_file_exists, default=None, metavar="FILE", ) parser.add_argument( 'FILE', help='Configuration file', nargs=1, type=argparse.FileType('r'), default=sys.stdin, ) return parser PKVF scal/template.py#!/usr/bin/env python3 # Copyright Louis Paternault 2011-2015 # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . 1 """Calendar generation""" import jinja2 import os import pkg_resources from scal import VERSION import scal def generate_tex(calendar, template=None, weeks=None): """Generate TeX code producing calendar represented in argument. :arg Calendar calendar: A :class:`Calendar` object. :arg str template: The name of a template to use. Use ``None`` for default template. """ if template is None: basename = "template.tex" dirname = os.path.dirname(pkg_resources.resource_filename( #pylint: disable=no-member "scal", os.path.join("data", "templates", basename) )) else: basename = os.path.basename(template) dirname = os.path.dirname(template) if weeks is None: weeks = scal.calendar.parse_weeks("none") environment = jinja2.Environment( loader=jinja2.FileSystemLoader(dirname) ) environment.block_start_string = '(*' environment.block_end_string = '*)' environment.variable_start_string = '((' environment.variable_end_string = '))' environment.comment_start_string = '(% comment %)' environment.comment_end_string = '(% endcomment %)' environment.line_comment_prefix = '%!' #environment.filters['escape_tex'] = _escape_tex environment.trim_blocks = True environment.lstrip_blocks = True return environment.get_template(basename).render({ #pylint: disable=maybe-no-member 'start': calendar.start, 'end': calendar.end, 'nb_months': calendar.months_count(), 'holidays': calendar.holidays, 'config': calendar.config, 'years': calendar.year_boundaries(), 'weeks': calendar.weeks(weeks['work'], weeks['iso']), 'version': "`scal` version {}".format(VERSION), }) PKdGX scal/data/templates/template.tex%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Copyright 2012 Robert Krause % Copyright 2014 Louis Paternault % License : Creative Commons Attribution License % % Produced by ((version)). % http://git.framasoft.org/spalax/scal % % Compile it using `lualatex` % % History: % This file has been posted by original author Robert Krause on TeXample.net % [1] on 13 July 2012. I (Louis Paternault) used it as a base for this % template, for the scal software. % % [1] http://www.texample.net/tikz/examples/a-calender-for-doublesided-din-a4/ % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \documentclass[10pt]{article} \IfFileExists{hyperref.sty}{ \usepackage[ pdftitle={Calendar for years (*for year in years|sort*) ((year)) (*endfor*) }, pdfcreator={LuaLaTeX, using a file generated by ((version))}, ]{hyperref} }{ % Hyperref not loaded } \usepackage{fontspec} \renewcommand{\familydefault}{\sfdefault} \usepackage[((config.lang))]{babel} \usepackage[((config.lang))]{translator} % Internationalized Month and Day names \usepackage{tikz} \usetikzlibrary{calc} \usetikzlibrary{calendar} \usepackage[((config.papersize)), landscape, margin=.5cm]{geometry} \newcommand{\cellwidth}{\textwidth/((nb_months))} \newcommand{\cellheight}{\textheight/34} \newcommand{\cellsep}{2pt} % Names of Holidays are inserted by employing this macro. Arguments: % - #1: First day of holidays % - #2: Holiday name \def\printholiday#1#2{ \node [anchor=north west, align=right, text width={\cellwidth-\cellsep-7pt}] at ($(cal-#1.north west)$) {\tiny{#2\par}}; } % Display weeks % - #1 Day in which week is to be written % - #2 Week number (as LaTeX code) \def\printweek#1#2{ \node [anchor=east, align=center, color=gray] at ($(cal-#1.east)$) {{#2\par}}; } % Display the year. Arguments are: % - #1: Year % - #2: First day of year % - #3: First day of last month of year \newcommand{\printyear}[3]{ \draw[fill=red!70, draw=none] ($(cal-#1-#2-01.north west)+(0, {2*\cellheight})$) rectangle ($(cal-#1-#3-01.south east)+(0, {2*\cellheight})$) node[midway, text=white]{\textbf{#1}}; } \pagestyle{empty} \begin{document} \begin{center} \begin{tikzpicture}[every day/.style={anchor = north}] \pgftransformyshift{\cellheight} \calendar[ dates=((start)) to ((end)), name=cal, day yshift = \cellheight, day code= { \node[name=\pgfcalendarsuggestedname,every day,shape=rectangle, minimum height= \cellheight, draw=black, text width = {\cellwidth-\cellsep-7pt}]{}; \draw ($(\pgfcalendarsuggestedname.west)+(0 em,0)$) node[anchor=west, color=gray]{\tikzdaytext}; \draw ($(\pgfcalendarsuggestedname.west)+(1.5em,0)$) node[anchor=west, color=gray]{\footnotesize \pgfcalendarweekdayshortname{\pgfcalendarcurrentweekday}}; }, execute before day scope= { \ifdate{day of month=1} { % Shift right \pgftransformxshift{\cellwidth} % Print month name \draw (0,0) node [shape=rectangle, minimum height= \cellheight, text width = {\cellwidth-\cellsep-7pt}, fill = red!70, text= white, draw = red!70, text centered] {\textbf{\pgfcalendarmonthname{\pgfcalendarcurrentmonth}}}; }{} \ifdate{workday} { % normal days are white \tikzset{every day/.style={fill=white}} % Holidays (* for holiday in holidays *) \ifdate{between=((holiday.start)) and ((holiday.end))}{% \tikzset{every day/.style={fill=gray!30}}}{} (* endfor *) }{} % Saturdays \ifdate{Saturday}{\tikzset{every day/.style={fill=red!10}}}{} % Sundays \ifdate{Sunday}{\tikzset{every day/.style={fill=red!20}}}{} }, execute at begin day scope= { % each day is shifted down according to the day of month \pgftransformyshift{-{\cellheight * \number\pgfcalendarcurrentday}} } ]; % Print name of Holidays (* for holiday in holidays if holiday.name *) \printholiday{((holiday.start))}{((holiday.name))} (* endfor *) % Print week numbers (* for week in weeks if week.work and week.iso *) \printweek{((week.date))}{((week.work)) / ((week.iso))} (* endfor *) (* for week in weeks if week.iso and not week.work *) \printweek{((week.date))}{((week.iso))} (* endfor *) (* for week in weeks if week.work and not week.iso*) \printweek{((week.date))}{((week.work))} (* endfor *) % Print years (* for year, boundaries in years.items() *) \printyear{((year))}{((boundaries[0]))}{((boundaries[1]))} (* endfor *) \end{tikzpicture} \end{center} \end{document} PK۳9Hu<<$Scal-0.3.0.dist-info/DESCRIPTION.rstscal — School year calendar generator ===================================== |sources| |pypi| |documentation| |license| I use this program about once a year to print a one-page school-year calendar. But it can be used to represent any calendar. It is heavily inspired by the simple yet powerful Robert Krause's `calendar `_, itself using the complex yet powerful Till Tantau's `TikZ `_ LaTeX package. Examples: - French school year: - 2015-2016: `zone A `__ (`source `__), `zone B `__ (`source `__), `zone C `__ (`source `__) - 2016-2017: `zone A `__ (`source `__), `zone B `__ (`source `__), `zone C `__ (`source `__) - 2017-2018: `zone A `__ (`source `__), `zone B `__ (`source `__), `zone C `__ (`source `__) What's new? ----------- See `changelog `_. Download and install -------------------- See the end of list for a (quick and dirty) Debian package. * Non-Python dependencies. This program produces LuaLaTeX code, but does not compile it. So, LaTeX is not needed to run this program. However, to compile the generated code, you will need a working LaTeX installation, with ``lualatex``, and LuaLaTeX packages `geometry `_, `babel `_, `tikz `_, `fontspec `_, and `translator` (provided by the `beamer `_ package). Those are provided by `TeXLive `_ on GNU/Linux, `MiKTeX `_ on Windows, and `MacTeX `_ on MacOS. * From sources: * Download: https://pypi.python.org/pypi/scal * Install (in a `virtualenv`, if you do not want to mess with your distribution installation system):: python3 setup.py install * From pip:: pip install scal * Quick and dirty Debian (and Ubuntu?) package This requires `stdeb `_ to be installed:: python3 setup.py --command-packages=stdeb.command bdist_deb sudo dpkg -i deb_dist/scal-_all.deb Documentation ------------- * The compiled documentation is available on `readthedocs `_ * To compile it from source, download and run:: cd doc && make html .. |documentation| image:: http://readthedocs.org/projects/scal/badge :target: http://scal.readthedocs.org .. |pypi| image:: https://img.shields.io/pypi/v/scal.svg :target: http://pypi.python.org/pypi/scal .. |license| image:: https://img.shields.io/pypi/l/scal.svg :target: http://www.gnu.org/licenses/gpl-3.0.html .. |sources| image:: https://img.shields.io/badge/sources-scal-brightgreen.svg :target: http://git.framasoft.org/spalax/scal PKӳ9H_$--%Scal-0.3.0.dist-info/entry_points.txt[console_scripts] scal = scal.__main__:main PK۳9HI3 ss"Scal-0.3.0.dist-info/metadata.json{"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Console", "Intended Audience :: Education", "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Topic :: Software Development :: Code Generators", "Topic :: Text Processing :: Markup :: LaTeX"], "extensions": {"python.commands": {"wrap_console": {"scal": "scal.__main__:main"}}, "python.details": {"contacts": [{"email": "spalax@gresille.org", "name": "Louis Paternault", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst"}, "project_urls": {"Home": "http://git.framasoft.org/spalax/scal"}}, "python.exports": {"console_scripts": {"scal": "scal.__main__:main"}}}, "extras": [], "generator": "bdist_wheel (0.26.0)", "license": "GPLv3 or any later version", "metadata_version": "2.0", "name": "Scal", "run_requires": [{"requires": ["jinja2"]}], "summary": "LaTeX generation of school year calendars", "version": "0.3.0"}PKӳ9HMYK1"Scal-0.3.0.dist-info/top_level.txtscal PK0QRF2Scal-0.3.0.dist-info/zip-safe PK۳9H}\\Scal-0.3.0.dist-info/WHEELWheel-Version: 1.0 Generator: bdist_wheel (0.26.0) Root-Is-Purelib: true Tag: py3-none-any PK۳9HiEScal-0.3.0.dist-info/METADATAMetadata-Version: 2.0 Name: Scal Version: 0.3.0 Summary: LaTeX generation of school year calendars Home-page: http://git.framasoft.org/spalax/scal Author: Louis Paternault Author-email: spalax@gresille.org License: GPLv3 or any later version Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Environment :: Console Classifier: Intended Audience :: Education Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+) Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Topic :: Software Development :: Code Generators Classifier: Topic :: Text Processing :: Markup :: LaTeX Requires-Dist: jinja2 scal — School year calendar generator ===================================== |sources| |pypi| |documentation| |license| I use this program about once a year to print a one-page school-year calendar. But it can be used to represent any calendar. It is heavily inspired by the simple yet powerful Robert Krause's `calendar `_, itself using the complex yet powerful Till Tantau's `TikZ `_ LaTeX package. Examples: - French school year: - 2015-2016: `zone A `__ (`source `__), `zone B `__ (`source `__), `zone C `__ (`source `__) - 2016-2017: `zone A `__ (`source `__), `zone B `__ (`source `__), `zone C `__ (`source `__) - 2017-2018: `zone A `__ (`source `__), `zone B `__ (`source `__), `zone C `__ (`source `__) What's new? ----------- See `changelog `_. Download and install -------------------- See the end of list for a (quick and dirty) Debian package. * Non-Python dependencies. This program produces LuaLaTeX code, but does not compile it. So, LaTeX is not needed to run this program. However, to compile the generated code, you will need a working LaTeX installation, with ``lualatex``, and LuaLaTeX packages `geometry `_, `babel `_, `tikz `_, `fontspec `_, and `translator` (provided by the `beamer `_ package). Those are provided by `TeXLive `_ on GNU/Linux, `MiKTeX `_ on Windows, and `MacTeX `_ on MacOS. * From sources: * Download: https://pypi.python.org/pypi/scal * Install (in a `virtualenv`, if you do not want to mess with your distribution installation system):: python3 setup.py install * From pip:: pip install scal * Quick and dirty Debian (and Ubuntu?) package This requires `stdeb `_ to be installed:: python3 setup.py --command-packages=stdeb.command bdist_deb sudo dpkg -i deb_dist/scal-_all.deb Documentation ------------- * The compiled documentation is available on `readthedocs `_ * To compile it from source, download and run:: cd doc && make html .. |documentation| image:: http://readthedocs.org/projects/scal/badge :target: http://scal.readthedocs.org .. |pypi| image:: https://img.shields.io/pypi/v/scal.svg :target: http://pypi.python.org/pypi/scal .. |license| image:: https://img.shields.io/pypi/l/scal.svg :target: http://www.gnu.org/licenses/gpl-3.0.html .. |sources| image:: https://img.shields.io/badge/sources-scal-brightgreen.svg :target: http://git.framasoft.org/spalax/scal PK۳9HScal-0.3.0.dist-info/RECORDScal-0.3.0.dist-info/DESCRIPTION.rst,sha256=G5RuDLS7jI-nWOri27wXIIrf_2vAeBkeKsTYdY-TS5k,4156 Scal-0.3.0.dist-info/METADATA,sha256=6z-VJtonUUFec5xz9pTdAIjaOTa3jPPUQxrSYxLJABU,5015 Scal-0.3.0.dist-info/RECORD,, Scal-0.3.0.dist-info/WHEEL,sha256=zX7PHtH_7K-lEzyK75et0UBa3Bj8egCBMXe1M4gc6SU,92 Scal-0.3.0.dist-info/entry_points.txt,sha256=aqTT-6E1UtyxBMetV21naj3bfe37F48lNYTOPn4r3-s,45 Scal-0.3.0.dist-info/metadata.json,sha256=G_9MSOxyd2C9HqFZ97xKT61fblcDC_e75qxog-GUHbs,1139 Scal-0.3.0.dist-info/top_level.txt,sha256=98Q5Yy5i_uAZgFae2J9-UD_Ib2jhcVvKPm67Vqqa8r0,5 Scal-0.3.0.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1 scal/__init__.py,sha256=MvGsGidqBacAwnUOLCDKlDCY7OlZ4mZSFbjZ0K876ds,868 scal/__main__.py,sha256=KP1UStds-AgnCj1Jf7rsc_fJYj6a0X2AcM6VwYNnRDc,1424 scal/calendar.py,sha256=DMq8c2k24icJ9cqSS-tDwMV30TSHEn-Z5FUtbaMp-I8,12321 scal/errors.py,sha256=qo6OqSEYSwwbKJEvr3AMGp4FBXqkf0aQeUlUJmAOZTA,1015 scal/options.py,sha256=M0HEjSuGogoqKQmZONV3Q9E3uq0Cw-9_GhIovySCY_U,2398 scal/template.py,sha256=ztmYjydSX-gcWieNHUmxOHxfS0SdLsUrwOpcS00tEcw,2493 scal/data/templates/template.tex,sha256=tNcWkolhWb1MyGkzoefmHN4mFJBwdhqzDTbUJrvVcjw,4601 PK{G@-ddscal/__init__.pyPKYFe^ِscal/__main__.pyPK[F!0!0P scal/calendar.pyPKHE%s9scal/errors.pyPK7TG%*^ ^ =scal/options.pyPKVF MGscal/template.pyPKdGX 8Qscal/data/templates/template.texPK۳9Hu<<$ocScal-0.3.0.dist-info/DESCRIPTION.rstPKӳ9H_$--%sScal-0.3.0.dist-info/entry_points.txtPK۳9HI3 ss"]tScal-0.3.0.dist-info/metadata.jsonPKӳ9HMYK1"yScal-0.3.0.dist-info/top_level.txtPK0QRF2UyScal-0.3.0.dist-info/zip-safePK۳9H}\\yScal-0.3.0.dist-info/WHEELPK۳9HiE%zScal-0.3.0.dist-info/METADATAPK۳9HScal-0.3.0.dist-info/RECORDPK+ϒ