Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F67025438
Attribute.py
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Wed, Jun 19, 12:05
Size
12 KB
Mime Type
text/x-python
Expires
Fri, Jun 21, 12:05 (2 d)
Engine
blob
Format
Raw Data
Handle
18330191
Attached To
R3596 pybliographer
Attribute.py
View Options
# This file is part of pybliographer
#
# Copyright (C) 1998-2006 Frederic GOBRY
# Email : gobry@pybliographer.org
#
# 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 2
# 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, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
""" Basic data types that can be used as attributes for a L{Record
<Pyblio.Store.Record>}.
Basic attributes of a record can be B{qualified} by one or more
additional sub-attributes. For instance, an attribute I{author} of
type L{Person} can have, for every Person instance, a sub-attribute of
type L{Date} that represents its birth date."""
import
string
,
re
,
urlparse
,
os
from
gettext
import
gettext
as
_
from
xml
import
sax
from
xml.sax.saxutils
import
escape
,
quoteattr
from
Pyblio
import
I18n
re_split
=
re
.
compile
(
r'\W+'
,
re
.
UNICODE
)
class
_Qualified
(
object
):
""" Mix-in class that provides qualifiers to attributes, making
them behave like composite data types (but not arbitrarily nested
data, though)"""
def
_xmlsubwrite
(
self
,
fd
,
offset
=
1
):
ws
=
' '
*
offset
for
k
,
vs
in
self
.
q
.
items
():
fd
.
write
(
ws
+
'<attribute id=
%s
>
\n
'
%
quoteattr
(
k
))
for
v
in
vs
:
v
.
xmlwrite
(
fd
,
offset
+
1
)
fd
.
write
(
'
\n
'
)
fd
.
write
(
ws
+
'</attribute>
\n
'
)
return
def
deep_equal
(
self
,
other
):
for
k
in
self
.
q
:
if
not
k
in
other
.
q
or
not
len
(
self
.
q
[
k
])
==
len
(
other
.
q
[
k
]):
return
False
for
x
,
y
in
zip
(
self
.
q
[
k
],
other
.
q
[
k
]):
if
not
x
.
deep_equal
(
y
):
return
False
for
k
in
other
.
q
:
if
not
k
in
self
.
q
:
return
False
return
True
def
is_complete
(
self
):
"""Returns True if the field has an actual value (ie, hasn't
been created by adding qualifiers only)"""
return
True
class
UnknownContent
(
_Qualified
):
"""
An invalid type.
It is used, when you add qualifiers before you add the main field
to a record. Trying to store it will raise an error.
"""
def
__init__
(
self
):
self
.
q
=
{}
def
xmlwrite
(
self
,
fd
,
offset
=
0
):
raise
Exceptions
.
ParserError
(
"Attribute.UnknownContent has qualifiers, "
\
"but is empty:
%s
"
%
self
.
q
)
def
deep_equal
(
self
,
other
):
if
not
isinstance
(
other
,
UnknownContent
):
return
False
return
_Qualified
.
deep_equal
(
self
,
other
)
def
is_complete
(
self
):
return
False
class
Person
(
_Qualified
):
''' A person name. '''
def
__init__
(
self
,
honorific
=
None
,
first
=
None
,
last
=
None
,
lineage
=
None
,
xml
=
None
):
self
.
q
=
{}
self
.
honorific
=
honorific
self
.
first
=
first
self
.
last
=
last
self
.
lineage
=
lineage
return
def
xmlread
(
k
,
xml
,
inside
=
False
):
p
=
k
()
for
f
in
(
'honorific'
,
'first'
,
'last'
,
'lineage'
):
setattr
(
p
,
f
,
xml
.
attrib
.
get
(
f
,
None
))
return
p
xmlread
=
classmethod
(
xmlread
)
def
xmlwrite
(
self
,
fd
,
offset
=
0
):
ws
=
' '
*
offset
data
=
[]
for
f
in
(
'honorific'
,
'first'
,
'last'
,
'lineage'
):
v
=
getattr
(
self
,
f
)
if
v
:
data
.
append
(
'
%s
=
%s
'
%
(
f
,
quoteattr
(
v
.
encode
(
'utf-8'
))))
data
=
' '
.
join
(
data
)
if
not
self
.
q
:
fd
.
write
(
ws
+
'<person
%s
/>'
%
data
)
else
:
fd
.
write
(
ws
+
'<person
%s
>
\n
'
%
data
)
self
.
_xmlsubwrite
(
fd
,
offset
+
1
)
fd
.
write
(
ws
+
'</person>'
)
return
def
index
(
self
):
idx
=
[]
for
x
in
(
self
.
first
,
self
.
last
):
if
x
:
idx
=
idx
+
map
(
string
.
lower
,
re_split
.
split
(
x
))
return
filter
(
None
,
idx
)
def
sort
(
self
):
return
(
u'
%s
\0
%s
'
%
(
self
.
last
or
''
,
self
.
first
or
''
))
.
lower
()
def
__eq__
(
self
,
other
):
return
self
.
last
==
other
.
last
and
\
self
.
first
==
other
.
first
and
\
self
.
honorific
==
other
.
honorific
and
\
self
.
lineage
==
other
.
lineage
def
__ne__
(
self
,
other
):
return
self
.
last
!=
other
.
last
or
\
self
.
first
!=
other
.
first
or
\
self
.
honorific
!=
other
.
honorific
or
\
self
.
lineage
!=
other
.
lineage
def
deep_equal
(
self
,
other
):
if
not
self
==
other
or
not
isinstance
(
other
,
Person
):
return
False
return
_Qualified
.
deep_equal
(
self
,
other
)
def
__repr__
(
self
):
return
"Person (
%s
,
%s
)"
%
(
repr
(
self
.
last
),
repr
(
self
.
first
))
def
__hash__
(
self
):
return
hash
((
self
.
last
,
self
.
first
,
self
.
lineage
,
self
.
honorific
))
class
Date
(
_Qualified
):
''' A date. '''
def
__init__
(
self
,
year
=
None
,
month
=
None
,
day
=
None
):
self
.
q
=
{}
self
.
year
=
year
self
.
month
=
month
self
.
day
=
day
return
def
xmlread
(
k
,
xml
):
d
=
k
()
for
f
in
(
'year'
,
'month'
,
'day'
):
v
=
xml
.
attrib
.
get
(
f
,
None
)
if
v
:
setattr
(
d
,
f
,
int
(
v
))
return
d
xmlread
=
classmethod
(
xmlread
)
def
xmlwrite
(
self
,
fd
,
offset
=
0
):
ws
=
' '
*
offset
data
=
[]
for
f
in
(
'year'
,
'month'
,
'day'
):
v
=
getattr
(
self
,
f
)
if
v
:
data
.
append
(
'
%s
="
%d
"'
%
(
f
,
v
))
fd
.
write
(
ws
+
'<date
%s
'
%
string
.
join
(
data
,
' '
))
if
self
.
q
:
fd
.
write
(
'>
\n
'
)
self
.
_xmlsubwrite
(
fd
,
offset
+
1
)
fd
.
write
(
ws
+
'</date>'
)
else
:
fd
.
write
(
'/>'
)
return
def
index
(
self
):
return
[]
def
sort
(
self
):
return
'
%.4d%.2d%.2d
'
%
(
self
.
year
or
0
,
self
.
month
or
0
,
self
.
day
or
0
)
def
__cmp__
(
self
,
other
):
if
not
isinstance
(
other
,
Date
):
return
1
for
x
,
y
in
((
self
.
year
,
other
.
year
),
(
self
.
month
,
other
.
month
),
(
self
.
day
,
other
.
day
)):
a
=
cmp
(
x
,
y
)
if
a
:
return
a
return
0
def
deep_equal
(
self
,
other
):
if
not
self
==
other
or
not
isinstance
(
other
,
Date
):
return
False
return
_Qualified
.
deep_equal
(
self
,
other
)
def
__hash__
(
self
):
return
hash
((
self
.
year
,
self
.
month
,
self
.
day
))
def
__repr__
(
self
):
return
'Date (year =
%s
, month =
%s
, day =
%s
)'
%
(
repr
(
self
.
year
),
repr
(
self
.
month
),
repr
(
self
.
day
))
class
Text
(
unicode
,
_Qualified
):
''' Textual data '''
def
__new__
(
cls
,
*
args
,
**
kwargs
):
obj
=
unicode
.
__new__
(
cls
,
*
args
,
**
kwargs
)
obj
.
q
=
{}
return
obj
def
xmlread
(
k
,
xml
):
content
=
xml
.
find
(
'./content'
)
if
content
is
not
None
:
return
k
(
content
.
text
)
else
:
return
k
(
xml
.
text
)
xmlread
=
classmethod
(
xmlread
)
def
xmlwrite
(
self
,
fd
,
offset
=
0
):
ws
=
' '
*
offset
if
self
.
q
:
fd
.
write
(
ws
+
'<text>
\n
'
)
fd
.
write
(
ws
+
' <content>
%s
</content>
\n
'
%
escape
(
self
.
encode
(
'utf-8'
)))
self
.
_xmlsubwrite
(
fd
,
offset
+
1
)
fd
.
write
(
ws
+
'</text>'
)
else
:
fd
.
write
(
ws
+
'<text>
%s
</text>'
%
escape
(
self
.
encode
(
'utf-8'
)))
return
def
index
(
self
):
idx
=
map
(
string
.
lower
,
re_split
.
split
(
self
))
return
filter
(
None
,
idx
)
def
sort
(
self
):
return
self
.
lower
()
def
deep_equal
(
self
,
other
):
if
self
!=
other
or
not
isinstance
(
other
,
Text
):
return
False
return
_Qualified
.
deep_equal
(
self
,
other
)
class
URL
(
unicode
,
_Qualified
):
''' An URL '''
def
__new__
(
cls
,
*
args
,
**
kwargs
):
obj
=
unicode
.
__new__
(
cls
,
*
args
,
**
kwargs
)
obj
.
q
=
{}
return
obj
def
xmlread
(
k
,
xml
):
return
k
(
xml
.
attrib
[
'href'
])
xmlread
=
classmethod
(
xmlread
)
def
xmlwrite
(
self
,
fd
,
offset
=
0
):
ws
=
' '
*
offset
fd
.
write
(
ws
+
'<url href=
%s
'
%
quoteattr
(
self
.
encode
(
'utf-8'
)))
if
self
.
q
:
fd
.
write
(
'>
\n
'
)
self
.
_xmlsubwrite
(
fd
,
offset
+
1
)
fd
.
write
(
ws
+
'</url>'
)
else
:
fd
.
write
(
'/>'
)
return
def
index
(
self
):
# do not index the document suffix, only the server name and document page
url
=
urlparse
.
urlparse
(
self
)
idx
=
re_split
.
split
(
url
[
1
])
+
\
re_split
.
split
(
os
.
path
.
splitext
(
url
[
2
])
[
0
])
return
filter
(
None
,
idx
)
def
sort
(
self
):
return
self
def
deep_equal
(
self
,
other
):
if
self
!=
other
or
not
isinstance
(
other
,
URL
):
return
False
return
_Qualified
.
deep_equal
(
self
,
other
)
class
ID
(
unicode
,
_Qualified
):
''' An external identifier '''
def
__new__
(
cls
,
*
args
,
**
kwargs
):
obj
=
unicode
.
__new__
(
cls
,
*
args
,
**
kwargs
)
obj
.
q
=
{}
return
obj
def
xmlread
(
k
,
xml
):
return
k
(
xml
.
attrib
[
'value'
])
xmlread
=
classmethod
(
xmlread
)
def
xmlwrite
(
self
,
fd
,
offset
=
0
):
ws
=
' '
*
offset
fd
.
write
(
ws
+
'<id value=
%s
'
%
quoteattr
(
self
.
encode
(
'utf-8'
)))
if
self
.
q
:
fd
.
write
(
'>
\n
'
)
self
.
_xmlsubwrite
(
fd
,
offset
+
1
)
fd
.
write
(
ws
+
'</id>'
)
else
:
fd
.
write
(
'/>'
)
return
def
index
(
self
):
return
[]
def
sort
(
self
):
return
self
def
deep_equal
(
self
,
other
):
if
self
!=
other
or
not
isinstance
(
other
,
ID
):
return
False
return
_Qualified
.
deep_equal
(
self
,
other
)
class
Txo
(
_Qualified
):
""" Element of a taxonomy.
In the simplest case, this can be seen as a value in a enumerated
set of possible values. The possible values are defined as
L{Pyblio.Schema.TxoItem}s, and are stored in the
L{Store.Database}, in the B{txo} attribute, and L{Store.Record}s
can contain Txo attributes which refer to these
L{Pyblio.Schema.TxoItem}s. Say you have a list of known document
types in the I{document-type} taxonomy. You can then affect the
document type to the I{type} attribute of a record with the
following operations:
>>> item = db.txo['document-type'].byname('article')
>>> record.add('type', item, Attribute.Txo)
"""
def
__init__
(
self
,
item
=
None
):
self
.
q
=
{}
if
item
:
self
.
group
=
item
.
group
self
.
id
=
item
.
id
else
:
self
.
group
=
None
self
.
id
=
None
return
def
xmlread
(
k
,
xml
):
txo
=
k
()
txo
.
group
=
xml
.
attrib
[
'group'
]
txo
.
id
=
int
(
xml
.
attrib
[
'id'
])
return
txo
xmlread
=
classmethod
(
xmlread
)
def
xmlwrite
(
self
,
fd
,
offset
=
0
):
ws
=
' '
*
offset
fd
.
write
(
ws
+
'<txo group="
%s
" id="
%d
"'
%
(
self
.
group
,
self
.
id
))
if
self
.
q
:
fd
.
write
(
'>
\n
'
)
self
.
_xmlsubwrite
(
fd
,
offset
+
1
)
fd
.
write
(
ws
+
'</txo>'
)
else
:
fd
.
write
(
'/>'
)
return
def
index
(
self
):
return
[
'
%s
/
%d
'
%
(
self
.
group
,
self
.
id
)
]
def
sort
(
self
):
return
'
%s
/
%d
'
%
(
self
.
group
,
self
.
id
)
def
__repr__
(
self
):
return
'Txo (
%s
,
%s
)'
%
(
`self.group`
,
`self.id`
)
def
__cmp__
(
self
,
other
):
try
:
return
cmp
(
self
.
group
,
other
.
group
)
or
cmp
(
self
.
id
,
other
.
id
)
except
AttributeError
:
# If 'other' is not of the proper type, simply consider
# 'self' as superior.
return
1
def
deep_equal
(
self
,
other
):
if
not
self
==
other
or
not
isinstance
(
other
,
Txo
):
return
False
return
_Qualified
.
deep_equal
(
self
,
other
)
def
__hash__
(
self
):
return
hash
((
self
.
group
,
self
.
id
))
# A mapping between class names and class objects
N_to_C
=
{
'person'
:
Person
,
'date'
:
Date
,
'text'
:
Text
,
'url'
:
URL
,
'id'
:
ID
,
'txo'
:
Txo
,
}
# A mapping from class objects to class names
C_to_N
=
{}
for
_k
,
_v
in
N_to_C
.
items
():
C_to_N
[
_v
]
=
_k
del
_k
,
_v
Event Timeline
Log In to Comment