<s> from __future__ import unicode_literals <EOL> from collections import defaultdict <EOL> import copy <EOL> import datetime <EOL> import json <EOL> import os <EOL> import re <EOL> import six <EOL> from . exceptions import TaxiException <EOL> @ six . python_2_unicode_compatible <EOL> class Project : <EOL> STATUS_NOT_STARTED = <NUM_LIT:0> <EOL> STATUS_ACTIVE = <NUM_LIT:1> <EOL> STATUS_FINISHED = <NUM_LIT:2> <EOL> STATUS_CANCELLED = <NUM_LIT:3> <EOL> STATUSES = { <EOL> STATUS_NOT_STARTED : '<STR_LIT>' , <EOL> STATUS_ACTIVE : '<STR_LIT>' , <EOL> STATUS_FINISHED : '<STR_LIT>' , <EOL> STATUS_CANCELLED : '<STR_LIT>' , <EOL> } <EOL> SHORT_STATUSES = { <EOL> STATUS_NOT_STARTED : '<STR_LIT:N>' , <EOL> STATUS_ACTIVE : '<STR_LIT:A>' , <EOL> STATUS_FINISHED : '<STR_LIT:F>' , <EOL> STATUS_CANCELLED : '<STR_LIT:C>' , <EOL> } <EOL> STR_TUPLE_REGEXP = r'<STR_LIT>' <EOL> def __init__ ( self , id , name , status = None , description = None , budget = None ) : <EOL> self . id = int ( id ) <EOL> self . name = name <EOL> self . activities = [ ] <EOL> self . status = int ( status ) if status is not None else None <EOL> self . description = description <EOL> self . budget = budget <EOL> self . aliases = { } <EOL> self . start_date = None <EOL> self . end_date = None <EOL> self . backend = None <EOL> def __str__ ( self ) : <EOL> if self . status in self . STATUSES : <EOL> status = self . STATUSES [ self . status ] <EOL> else : <EOL> status = '<STR_LIT>' <EOL> start_date = self . get_formatted_date ( self . start_date ) <EOL> if start_date is None : <EOL> start_date = '<STR_LIT>' <EOL> end_date = self . get_formatted_date ( self . end_date ) <EOL> if end_date is None : <EOL> end_date = '<STR_LIT>' <EOL> return """<STR_LIT>""" % ( self . id , self . name , status , start_date , end_date , <EOL> self . budget , self . description ) <EOL> def get_formatted_date ( self , date ) : <EOL> if date is not None : <EOL> try : <EOL> formatted_date = date . strftime ( '<STR_LIT>' ) <EOL> except ValueError : <EOL> formatted_date = None <EOL> else : <EOL> formatted_date = None <EOL> return formatted_date <EOL> def add_activity ( self , activity ) : <EOL> self . activities . append ( activity ) <EOL> def get_activity ( self , id ) : <EOL> for activity in self . activities : <EOL> if activity . id == id : <EOL> return activity <EOL> return None <EOL> def is_active ( self ) : <EOL> return ( self . status == self . STATUS_ACTIVE and <EOL> ( self . start_date is None or <EOL> self . start_date <= datetime . date . today ( ) ) and <EOL> ( self . end_date is None or self . end_date >= <EOL> datetime . date . today ( ) ) ) <EOL> def get_short_status ( self ) : <EOL> if self . status not in self . SHORT_STATUSES : <EOL> return '<STR_LIT:?>' <EOL> return self . SHORT_STATUSES [ self . status ] <EOL> @ classmethod <EOL> def str_to_tuple ( cls , string ) : <EOL> """<STR_LIT>""" <EOL> matches = re . match ( cls . STR_TUPLE_REGEXP , string ) <EOL> if not matches or len ( matches . groups ( ) ) != <NUM_LIT:2> : <EOL> return None <EOL> return tuple ( <EOL> [ int ( item ) if item else None for item in matches . groups ( ) ] <EOL> ) <EOL> @ classmethod <EOL> def tuple_to_str ( cls , t ) : <EOL> """<STR_LIT>""" <EOL> if len ( t ) != <NUM_LIT:2> : <EOL> return None <EOL> if t [ <NUM_LIT:1> ] is not None : <EOL> return u'<STR_LIT>' % t <EOL> else : <EOL> return unicode ( t [ <NUM_LIT:0> ] ) <EOL> class Activity : <EOL> def __init__ ( self , id , name , price ) : <EOL> self . id = int ( id ) <EOL> self . name = name <EOL> self . price = price <EOL> class ProjectsDb : <EOL> PROJECTS_FILE = '<STR_LIT>' <EOL> def __init__ ( self , path ) : <EOL> self . path = path <EOL> self . projects_database_file = os . path . join ( self . path , <EOL> self . PROJECTS_FILE ) <EOL> self . _projects_by_id_cache = None <EOL> self . _projects_cache = None <EOL> def get_projects ( self ) : <EOL> if self . _projects_cache is not None : <EOL> return self . _projects_cache <EOL> try : <EOL> if not os . stat ( self . projects_database_file ) . st_size : <EOL> return [ ] <EOL> except OSError : <EOL> return [ ] <EOL> with open ( self . projects_database_file , '<STR_LIT:r>' ) as projects_db : <EOL> try : <EOL> lpdb = json . load ( projects_db , cls = LocalProjectsDbDecoder ) <EOL> except ( UnicodeDecodeError , ValueError ) : <EOL> raise OutdatedProjectsDbException ( ) <EOL> if lpdb . VERSION < LocalProjectsDb . VERSION : <EOL> raise OutdatedProjectsDbException ( ) <EOL> self . _projects_cache = lpdb . projects <EOL> return lpdb . projects <EOL> def update ( self , projects ) : <EOL> lpdb = LocalProjectsDb ( projects ) <EOL> with open ( self . projects_database_file , '<STR_LIT:w>' ) as output : <EOL> json . dump ( lpdb . get_dump_object ( ) , output ) <EOL> self . _projects_cache = None <EOL> self . _projects_by_id_cache = None <EOL> def search ( self , search , active_only = False , backend = None ) : <EOL> projects = self . get_projects ( ) <EOL> found_list = [ ] <EOL> for project in projects : <EOL> found = True <EOL> for s in search : <EOL> s = s . lower ( ) <EOL> found = ( project . name . lower ( ) . find ( s ) > - <NUM_LIT:1> or <EOL> str ( project . id ) == s ) <EOL> if not found : <EOL> break <EOL> found = found and ( backend is None or project . backend == <EOL> backend ) <EOL> if found : <EOL> if not active_only or project . is_active ( ) : <EOL> found_list . append ( project ) <EOL> return found_list <EOL> def get ( self , id , backend = None ) : <EOL> if self . _projects_by_id_cache is None : <EOL> projects = self . get_projects ( ) <EOL> self . _projects_by_id_cache = defaultdict ( list ) <EOL> for project in projects : <EOL> self . _projects_by_id_cache [ project . id ] . append ( project ) <EOL> for project in self . _projects_by_id_cache . get ( id , [ ] ) : <EOL> if backend is None or project . backend == backend : <EOL> return project <EOL> return None <EOL> def mapping_to_project ( self , mapping ) : <EOL> project = self . get ( mapping . mapping [ <NUM_LIT:0> ] , mapping . backend ) <EOL> if not project : <EOL> return ( None , None ) <EOL> activity = project . get_activity ( mapping . mapping [ <NUM_LIT:1> ] ) <EOL> if not activity : <EOL> return ( project , None ) <EOL> return ( project , activity ) <EOL> class LocalProjectsDb : <EOL> VERSION = <NUM_LIT:2> <EOL> def __init__ ( self , projects = None ) : <EOL> if not projects : <EOL> projects = [ ] <EOL> self . projects = projects <EOL> def get_dump_object ( self ) : <EOL> return { <EOL> '<STR_LIT>' : self . VERSION , <EOL> '<STR_LIT>' : [ <EOL> self . dump_project ( project ) for project in self . projects <EOL> ] <EOL> } <EOL> def dump_project ( self , project ) : <EOL> project_dict = copy . copy ( project . __dict__ ) <EOL> for date_type in [ '<STR_LIT>' , '<STR_LIT>' ] : <EOL> if project_dict [ date_type ] is not None : <EOL> project_dict [ date_type ] = project_dict [ date_type ] . isoformat ( ) <EOL> project_dict [ '<STR_LIT>' ] = [ <EOL> activity . __dict__ for activity in project_dict [ '<STR_LIT>' ] <EOL> ] <EOL> return project_dict <EOL> class LocalProjectsDbDecoder ( json . JSONDecoder ) : <EOL> def decode ( self , s ) : <EOL> s = super ( LocalProjectsDbDecoder , self ) . decode ( s ) <EOL> projects = s [ '<STR_LIT>' ] <EOL> projects_copy = [ ] <EOL> for project in projects : <EOL> project [ '<STR_LIT>' ] = [ <EOL> Activity ( activity [ '<STR_LIT:id>' ] , activity [ '<STR_LIT:name>' ] , activity [ '<STR_LIT>' ] ) <EOL> for activity in project [ '<STR_LIT>' ] <EOL> ] <EOL> for date_type in [ '<STR_LIT>' , '<STR_LIT>' ] : <EOL> if project [ date_type ] is not None : <EOL> project [ date_type ] = datetime . datetime . strptime ( <EOL> project [ date_type ] , '<STR_LIT>' ) . date ( ) <EOL> p_copy = Project ( project [ '<STR_LIT:id>' ] , project [ '<STR_LIT:name>' ] ) <EOL> p_copy . __dict__ . update ( project ) <EOL> projects_copy . append ( p_copy ) <EOL> lpdb = LocalProjectsDb ( projects_copy ) <EOL> lpdb . VERSION = s [ '<STR_LIT>' ] <EOL> return lpdb <EOL> class OutdatedProjectsDbException ( TaxiException ) : <EOL> def __init__ ( self , * args , ** kwargs ) : <EOL> self . message = ( <EOL> "<STR_LIT>" <EOL> "<STR_LIT>" <EOL> ) <EOL> super ( OutdatedProjectsDbException , self ) . __init__ ( self . message , <EOL> * args , ** kwargs ) </s>
