#!/usr/bin/env python # -*- coding: utf-8 -*- # DEMO # - Script bør alltid inkludere hashbang og tegnsett ↑ # - I tillegg bør den ha en lisenstekst ↓ # Copyright 2015-2019 University of Oslo, Norway # # This file is part of Cerebrum. # # Cerebrum 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 2 of the License, or # (at your option) any later version. # # Cerebrum 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 Cerebrum; if not, write to the Free Software Foundation, # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. # DEMO # - Deretter bør den ha en kort docstring som forklarer bruk og oppførsel """ This is a demo script that explains how to structure imports, exports and maintenance-tasks in Cerebrum. """ import argparse import logging from mx.DateTime import now import cereconf import Cerebrum.logutils import Cerebrum.logutils.options import Cerebrum.utils.argutils from Cerebrum.Utils import Factory from Cerebrum.file import AtomicFileWriter logger = logging.getLogger(__name__) # DEMO # - Ting som typisk vi vil måtte endre, bør være enkle å endre på # - Her: Hvilken expire_date skal settes? def get_new_expire_date(account, default=None): """Get the new expire date for an account. :type account: Cerebrum.Account :param account: The account to calculate expire date for. :type default: mx.DateTime.DateTime :param default: The fallback value if no new expire date is found. """ if account.account_name == cereconf.INITIAL_ACCOUNTNAME: return None return (now() + 365).rebuild(hour=0, minute=0, second=0) # DEMO # - Ting som typisk vi vil måtte endre, bør være enkle å endre på # - Her: Hvem skal expire_date endres for? def get_candidates(db): """Generate account objects for accounts without expire_date.""" ac = Factory.get('Account')(db) seen = 0 for a in ac.search(): seen += 1 if not a['expire_date']: ac.clear() ac.find(a['account_id']) yield ac, seen def set_new_expire_date(account, expire_date): """Sets a new expire date for all candidates.""" account.expire_date = expire_date account.write_db() logger.debug("Set new expire date for %s: %s", account.account_name, account.expire_date) def alter_and_report(db, filename): """Reads info from `db' and generates file export `filename'. :param Cerebrum.Database db: The database connection :param basestring filename: The name of the file to write. """ # DEMO # - Alle eksportscripts som skriver til fil, bør benytte AtomicFileWriter, # SimilarSizeWriter e.l. changed = 0 with AtomicFileWriter(filename) as f: for account, no in get_candidates(db): changed += 1 set_new_expire_date(account, get_new_expire_date(account)) f.write("%s:%s" % (account.account_name, account.expire_date)) logger.info("Updated expire date on %d of %d accounts", changed, no) def main(args=None): """Main script runtime. This parses arguments and handles the database transaction. """ parser = argparse.ArgumentParser(description=__doc__) # DEMO # - Alle scripts som leser fra eller skriver til fil, bør ha en opsjon for # å angi filnavn. Filnavnet kan godt ha default-verdi parser.add_argument('-f', '--file', dest='fname', required=True, metavar='', help='Write export data to ') parser.add_argument('-e', '--exit', metavar='', help="Fail with message ") # DEMO: # - Alle scripts som utfører endringer, bør ha et `--commit'-flagg. # - Default-oppførsel for scripts bør være å *ikke* utføre endringer # - Bruk gjerne argutils.add_commit_args() for å legge på dette Cerebrum.utils.argutils.add_commit_args(parser, default=False) # DEMO: # - Alle scripts må ta inn logger-konfigurasjon # - Dette gjøres med Cerebrum.logutils Cerebrum.logutils.options.install_subparser(parser) args = parser.parse_args(args) # DEMO: # - Logg-konfigurasjon må settes opp så tidlig som mulig # - Bruk 'cronjob' som default-preset Cerebrum.logutils.autoconf('cronjob', args) # DEMO: Logg start av script. logger.info("Start %s", parser.prog) logger.debug("args: %s", repr(args)) db = Factory.get('Database')() # DEMO # - Alle scripts som utfører database-endring må angi et change-program db.cl_init(change_program=parser.prog) if args.exit: # DEMO # - For å avslutte scripts, bør SystemExit benyttes. # - Scripts bør kun avsluttes fra `main' eller tilsvarende. # - Why? SystemExit kan fanges opp, f.eks. hvis man kjører script fra # et interaktivt konsoll. raise SystemExit(args.exit) try: alter_and_report(db, args.fname) except Exception: logger.error("Unexpected exception", exc_info=1) db.rollback() raise if args.commit: logger.info("Commiting changes") db.commit() else: logger.info("Rolled back changes") db.rollback() # DEMO: Logg resultat og script-slutt: logger.info("Report written to %r", args.fname) logger.info("Done %s", parser.prog) # DEMO # - Alle scripts må teste om de er invokert som scripts, og kun kjøres dersom # dette er tilfelle. # - Alle scripts bør logge start-tid og stopp-tid if __name__ == '__main__': main() # DEMO: Eksempel på bruk # Dersom dette overholdes, vil vi ha mulighet til å overstyre deler av scriptet # fra interaktiv python-sesjon, samt fra testscript. # # $ python # # >>> # Make changes to bootstrap_account # >>> import cereconf # >>> cereconf.INITIAL_ACCOUNTNAME = None # >>> # >>> # Use console logger # >>> from Cerebrum.Utils import Factory # >>> Factory.get_logger('console') # >>> # >>> # Don't run on exec, and don't screw up globals/locals # >>> example = dict(__name__='test', __file__='example.py') # >>> execfile('example.py', example) # >>> # >>> example.get('main')("-f test.csv".split()) # INFO 2015-02-16 16:44:45 START # DEBUG 2015-02-16 16:44:45 Set new expire date for bootstrap_account: \ # 2016-02-16 00:00:00.00 # INFO 2015-02-16 16:44:45 Changed expire_date on 1 of 1 accounts # INFO 2015-02-16 16:44:45 Rolled back changes # INFO 2015-02-16 16:44:45 DONE # >>> try: # ... example.get('main')('-e foo'.split()) # ... except SystemExit, e: # ... pass # >>>