root/pdw/pd/__init__.py @ 325:61a8069c7b94

Revision 325:61a8069c7b94, 5.1 KB (checked in by acracia, 6 months ago)

changes to the api page, not taking the input and processing it with the calculators.
several other changes added to the model to process from dicts and to dicts

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()
60def float_date(year, month=0, day=0):
61    return swiss.date.FlexiDate(year, month, day).as_float()
62
63def determine_status(work, jurisdiction):
64    # now dispatch on jurisdiction (+ work type?)
65    # note two letter country codes based on ISO 3166
66    #
67    if jurisdiction == 'us':
68        pd_calculator = CalculatorUnitedStates
69    elif jurisdiction == 'ca':
70        pd_calculator = CalculatorCanada
71    elif jurisdiction in ('uk', 'gb') :
72        pd_calculator = CalculatorUk
73    else:
74        logger.error('Jurisdiction "%s" not currently supported. Try us,ca,uk' % jurisdiction)
75        assert 0
76    return pd_calculator().get_work_status(work)
77
78def determine_status_from_raw(json_data):
79    '''
80    To create a Work object and analize its pd status from a
81    python or json dict
82    '''
83
84    params = json.loads(json_data)
85    jur = params['jurisdiction'] 
86
87    work =  pdw.model.Work.from_dict(params['work'])
88
89    calculation = determine_status(work, jur)
90    result = json.dumps({'pd_probability': calculation.pd_prob,
91                        'confidence': 1-calculation.uncertainty,
92                        'log': calculation.log,
93                        'input': params},indent=2)
94    return result
95
96
97class CalcResult(object):
98    '''A CalcResult object is returned by the calculator
99    '''
100    def __init__(self):
101        self.calc_finished = False
102        self.date_pd = None
103        self.pd_prob = 0.0 # P(is PD)
104        self.uncertainty = 0.0
105        self.log = [] # strings
106
107    def __str__(self):
108        return "date_pd=%s pd_prob=%s log=%s" % (self.date_pd, self.pd_prob, self.log)
109
110class CalculatorBase(object):
111    """A Public Domain Calculator
112    when=None means today's date
113    """
114    def __init__(self, when):
115        self.author_list = None
116        if when:
117          self._now = when
118        else:
119            self._now = float_date(datetime.date.today().year)
120   
121    def get_work_status(self, work):
122        self.calc_result = CalcResult()
123        self.work = work
124
125    def get_author_list(self, parcel):
126        if self.author_list == None:
127            self.author_list = []
128            for person in self.work.persons:
129                self.author_list.append(person.name)
130        return self.author_list
131
132    def calc_anon(self):
133        self.calc_result.is_anon = False
134        for person in self.work.persons:
135            if person.name.lower() in ('anon', 'anon.', 'anonymous') :
136                self.calc_result.is_anon = True
137
138    def calc_death_dates(self):
139        death_dates = [] # list of: (name, float date)
140        names = []
141        most_recent_death_date = 0.0
142        for person in self.work.persons:
143            death_date = person.death_date_ordered
144            # if we have no deathdate but do have a birthdate, assume
145            # death OLDEST_PERSON years after birth
146            if not death_date and person.birth_date_ordered:
147                death_date = person.birth_date_ordered + OLDEST_PERSON
148                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))
149            death_dates.append((person.name, death_date))
150            if death_date and death_date > most_recent_death_date:
151                most_recent_death_date = death_date
152        an_author_lives = False
153        for name, death_date in death_dates:
154            if not death_date:
155                # no birthday
156                # alive: big assumption!
157                self.calc_result.log.append('Author "%s" death date not given - assuming alive (!)' % name)
158                an_author_lives = True
159
160        self.calc_result.death_dates = death_dates
161        self.calc_result.most_recent_death_date = most_recent_death_date
162        self.calc_result.an_author_lives = an_author_lives
163
164from uk import *
165from us import *
166from ca import *
167from fast import *
Note: See TracBrowser for help on using the browser.