root/pdw/pd/__init__.py @ 326:46fe057f2605

Revision 326:46fe057f2605, 5.6 KB (checked in by acracia, 6 months ago)

[api]to_dict method on the model, tailored to use as input of the api

Line 
1"""Determine copyright status of works given relevant information such as
2creator death date.
3
4Remarks
5=======
6
7Often cannot calculate PD with certainty (at least in an automated process). Different kinds of uncertainty:
8
9  * Do not know persons associated with work (with certainty or at all)
10  * Do not know their death dates (may or may not know birth dates)
11  * Do not know when work was published
12  * etc
13
14And this is even assuming we have identified the work (and/or whether it is a
15translation, critical edition etc etc).
16
17This uncertainty must therefore be presented. Core features
18
19  * PD/Copyright status
20  * Level of uncertainty ...
21  * Comments
22  * Compressed comments/Standard flags
23
24Suggestions for flags:
25  * normalized title
26  * notes
27  * translation
28
29def determine_status(work, jurisdiction, when):
30    # now dispatch on jurisdiction (+ work type?)
31
32class CopyrightStatus:
33    # Flags etc
34
35class CalculatorBase:
36    def get_work_status(self, work):
37
38class CalculatorUK(CalculatorBase):
39    pass
40"""
41import logging
42import datetime
43
44import swiss
45try:
46    import json
47except ImportError:
48    import simplejson as json
49
50#from sqlalchemy import orm
51import pdw
52
53
54logger = logging.getLogger('pdw.pd')
55
56
57OLDEST_PERSON = 100
58
59now = datetime.datetime.now()
60
61def float_date(year, month=0, day=0):
62    '''to convert a date in a float type'''
63    return swiss.date.FlexiDate(year, month, day).as_float()
64
65def determine_status(work, jurisdiction):
66    # now dispatch on jurisdiction (+ work type?)
67    # note two letter country codes based on ISO 3166
68    # need to add 'when' parameter here and deeper
69    if jurisdiction == 'us':
70        pd_calculator = CalculatorUnitedStates
71    elif jurisdiction == 'ca':
72        pd_calculator = CalculatorCanada
73    elif jurisdiction in ('uk', 'gb') :
74        pd_calculator = CalculatorUk
75    else:
76        logger.error('Jurisdiction "%s" not currently supported. Try us,ca,uk' % jurisdiction)
77        assert 0
78    return pd_calculator().get_work_status(work)
79
80def determine_status_from_raw(json_data):
81    '''
82    To create a Work object and analize its pd status from a
83    python or json dict
84    @param  params: json formatted string
85    @type   params: string
86    '''
87    params = json.loads(json_data)
88    jur = params['jurisdiction'] 
89
90    work =  pdw.model.Work.from_dict(params['work'])
91
92    calculation = determine_status(work, jur)
93    result = json.dumps({'pd_probability': calculation.pd_prob,
94                        'confidence': 1-calculation.uncertainty,
95                        'log': calculation.log,
96                        'input': params},indent=2)
97    return result
98
99
100class CalcResult(object):
101    '''A CalcResult object is returned by the calculator
102    '''
103    def __init__(self):
104        self.calc_finished = False
105        self.date_pd = None
106        self.pd_prob = 0.0 # P(is PD)
107        self.uncertainty = 0.0
108        self.log = [] # strings
109
110    def __str__(self):
111        return "date_pd=%s pd_prob=%s log=%s" % (self.date_pd, self.pd_prob, self.log)
112
113    @classmethod
114    def to_dict(cls, self):
115        '''Creates a dict result to give back as json in the api
116        '''
117        out_dict = { 'confidence': 1-self.uncertainty,
118                    'pd probability': self.pd_prob,
119                    'date pd': self.date_pd,
120                    'log': self.log,
121                   }
122        return out_dict
123#TODO
124
125class CalculatorBase(object):
126    """A Public Domain Calculator
127    when=None means today's date
128    """
129    def __init__(self, when):
130        self.author_list = None
131        self.death_dates = []
132        self.names = []
133        if when:
134            self._now = when
135        else:
136            self._now = float_date(datetime.date.today().year)
137   
138    def get_work_status(self, work):
139        self.calc_result = CalcResult()
140        self.work = work
141
142    def get_author_list(self, parcel):
143        if self.author_list == None:
144            self.author_list = []
145            for person in self.work.persons:
146                self.author_list.append(person.name)
147        return self.author_list
148
149    def calc_anon(self):
150        self.calc_result.is_anon = False
151        for person in self.work.persons:
152            if person.name.lower() in ('anon', 'anon.', 'anonymous') :
153                self.calc_result.is_anon = True
154
155    def calc_death_dates(self):
156        death_dates = [] # list of: (name, float date)
157        names = []
158        most_recent_death_date = 0.0
159        for person in self.work.persons:
160            death_date = person.death_date_ordered
161            # if we have no deathdate but do have a birthdate, assume
162            # death OLDEST_PERSON years after birth
163            if not death_date and person.birth_date_ordered:
164                death_date = person.birth_date_ordered + OLDEST_PERSON
165                self.calc_result.log.append('Author "%s" death date not given - assuming died %s years after birth (%s + %s = %s)' % (person.name, OLDEST_PERSON, person.birth_date_ordered, OLDEST_PERSON, death_date))
166            death_dates.append((person.name, death_date))
167            if death_date and death_date > most_recent_death_date:
168                most_recent_death_date = death_date
169        an_author_lives = False
170        for name, death_date in death_dates:
171            if not death_date:
172                # no birthday
173                # alive: big assumption!
174                self.calc_result.log.append('Author "%s" death date not given - assuming alive (!)' % name)
175                an_author_lives = True
176
177        self.calc_result.death_dates = death_dates
178        self.calc_result.most_recent_death_date = most_recent_death_date
179        self.calc_result.an_author_lives = an_author_lives
180
181from uk import *
182from us import *
183from ca import *
184from fast import *
Note: See TracBrowser for help on using the browser.