![]() |
#1 |
Wizard
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 4,004
Karma: 177841
Join Date: Dec 2009
Device: WinMo: IPAQ; Android: HTC HD2, Archos 7o; Java:Gravity T
|
For Charles/Chaley Merging user defined metadata
Charles,
While reading one of the recent threads, I realized that my Merge code was written before your custom column code. The merge code finds the first record selected (the "dest" destination record), then loops through the other selected book records (the "src" source records) in the order they were selected. For each src record, it copies the book formats in that record (provided that format doesn't already exist in the dest record) into the dest record. Then it loops through the src records again to merge in the metadata. For each type of metadata there is a check to see if it exists in the source metadata information (src_mi), but not in the dest (dest_mi), and if so, it's written into the dest record. It occurred to me that there are no checks (at least none written by me) for user defined metadata. Thus, merge would lose that data if it's not in the src record. Some types of metadata are handled in a special way (Comments are appended, authors may be "Unknown," so they exist, but are still handled as if they don't, etc.) All this "action" happens starting at line 802 of calibre\gui2\actions.py (pun not intended) in the merge_metadata(self, dest_id, src_ids) function. Here's a quick example of the merger of the cover: Code:
if src_mi.cover and not dest_mi.cover: dest_mi.cover = src_mi.cover Thanks. http://bugs.calibre-ebook.com/ticket/6120 Last edited by Starson17; 07-07-2010 at 10:09 AM. |
![]() |
![]() |
![]() |
#2 |
Grand Sorcerer
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 12,346
Karma: 8012652
Join Date: Jan 2010
Location: Notts, England
Device: Kobo Libra 2
|
Will do, but perhaps not for a few days. My wife found me a short consulting gig, and in a fit of madness I said yes. Now I must deliver on it.
![]() |
![]() |
![]() |
Advert | |
|
![]() |
#3 | |
Wizard
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 4,004
Karma: 177841
Join Date: Dec 2009
Device: WinMo: IPAQ; Android: HTC HD2, Archos 7o; Java:Gravity T
|
Quote:
![]() (Maybe "a few minutes" to do this was excessively optimistic, even for one of your talents ![]() |
|
![]() |
![]() |
![]() |
#4 |
Grand Sorcerer
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 12,346
Karma: 8012652
Join Date: Jan 2010
Location: Notts, England
Device: Kobo Libra 2
|
Actually, it probably is a few minutes.
![]() Look at the new class library.field_metadata, available as db.field_metadata. This a dict, keyed by the attribute name. The data fetched using the key has everything needed, including the datatype and its column number for fetching and storing the information. Something like: Code:
for key in db.field_metadata: if db.field_metadata[key]['is_custom']: col_num = db.field_metadata[key]['col_num'] # now do what is needed, according to type. rec_index is used # to get the value you are working with. something like from_record_value = db.get_custom(from_id, num=col_num) # process ... set_custom(to_id, val, num=col_num) |
![]() |
![]() |
![]() |
#5 | |
Wizard
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 4,004
Karma: 177841
Join Date: Dec 2009
Device: WinMo: IPAQ; Android: HTC HD2, Archos 7o; Java:Gravity T
|
Show off
![]() Quote:
Can you think of any of your field types that need special handling? I've forgotten all of the different types, but if you have one for text, like comments, should a src be appended to the dest or ignored? Any other types that should be appended or that have defaults that should be overwritten (like the default author "Unknown")? |
|
![]() |
![]() |
Advert | |
|
![]() |
#6 | |||
Grand Sorcerer
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 12,346
Karma: 8012652
Join Date: Jan 2010
Location: Notts, England
Device: Kobo Libra 2
|
Quote:
If you are going to play with standard fields, then you will want to know about field_metadata[key]['rec_index']. That field is the index into the _data record. You would use db.get(id, rec_index, row_is_id=True) (found in library.caches.py) to get the value for that field for a given db_id. Don't use db.set function in caches.py, because the data won't be written to the DB. Quote:
My guess is that text (non-tag, is_multiple=False), bool, int, float, and date columns should overwrite. Make sense to you? Quote:
|
|||
![]() |
![]() |
![]() |
#7 | |||||
Wizard
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 4,004
Karma: 177841
Join Date: Dec 2009
Device: WinMo: IPAQ; Android: HTC HD2, Archos 7o; Java:Gravity T
|
Quote:
Quote:
Quote:
Quote:
Quote:
There seem to be 4 types of text Text has:
As to series-like text, how does this differ from plain-jane text? I'm thinking of someone who has set up a secondary custom series in one field with an associated (in his mind) number field for ordering. It looks like even if the series-like text field is associated with an int or float, it would still be OK to treat the fields independently. As long as the user enters something in his number field when he enters something in the series-like text field, it wouldn't be overwritten and the pair wouldn't be decoupled. |
|||||
![]() |
![]() |
![]() |
#8 | ||
Grand Sorcerer
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 12,346
Karma: 8012652
Join Date: Jan 2010
Location: Notts, England
Device: Kobo Libra 2
|
Quote:
Quote:
You might not notice the pairing for series custom fields. These fields have two pieces of information. The first is the series name, which acts like a text (is_multiple=False) field. However, in this case the index is stored in the connection record in the DB, which makes it (sort-of) a column in the books table. You can get the value of the series field from the book view -- field_metadata.cc_series_index_column_for() will give you the field number -- and using db.get_custom_extra() (in custom_columns.py). The method db.set_custom() has a keyword parameter used for setting the index field at the same time the series is set. |
||
![]() |
![]() |
![]() |
#9 | ||
Wizard
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 4,004
Karma: 177841
Join Date: Dec 2009
Device: WinMo: IPAQ; Android: HTC HD2, Archos 7o; Java:Gravity T
|
Quote:
Quote:
Again, thanks for the details. |
||
![]() |
![]() |
![]() |
#10 | |
Wizard
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 4,004
Karma: 177841
Join Date: Dec 2009
Device: WinMo: IPAQ; Android: HTC HD2, Archos 7o; Java:Gravity T
|
Quote:
I looked at this after we spoke. I saw a field that I think was called "datatype" that was populated with one of the 9 types of data that could be specified as user-defined data. Does there happen to be a defined list of all datatypes that I can cycle through in a for: loop, something like: Code:
for datatype in list_of_all_available_datatypes: Thanks. |
|
![]() |
![]() |
![]() |
#11 |
Grand Sorcerer
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 12,346
Karma: 8012652
Join Date: Jan 2010
Location: Notts, England
Device: Kobo Libra 2
|
Yes, there is, but it is buried in the custom column code.
It is an excellent idea to add such a declaration to FieldMetadata, specifically Code:
VALID_DATA_TYPES = frozenset(['rating', 'text', 'comments', 'datetime',
'int', 'float', 'bool', 'series'])
Edit: Code has been pushed and merged into the trunk. Last edited by chaley; 07-16-2010 at 01:00 PM. |
![]() |
![]() |
![]() |
#12 |
Wizard
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 4,004
Karma: 177841
Join Date: Dec 2009
Device: WinMo: IPAQ; Android: HTC HD2, Archos 7o; Java:Gravity T
|
There are 8 there. There are 9 in the pulldown list of new field types the user can create. I vaguely recall a "text*" datatype. I suspected it was the series name and indicated there was a related series number. Most of the other types seem self explanatory. Did I miscount or recall incorrectly?
|
![]() |
![]() |
![]() |
#13 |
Grand Sorcerer
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 12,346
Karma: 8012652
Join Date: Jan 2010
Location: Notts, England
Device: Kobo Libra 2
|
The pulldown distinguishes between text/is_multiple=true & false. Tags & single-entry fields have the same underlying type.
|
![]() |
![]() |
![]() |
#14 |
Wizard
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 4,004
Karma: 177841
Join Date: Dec 2009
Device: WinMo: IPAQ; Android: HTC HD2, Archos 7o; Java:Gravity T
|
Charles, two questions:
Code:
from_record_value = db.get_custom(from_id, num=col_num) set_custom(to_id, val, num=col_num) Is there an easy way to merge tag-like text from two records when is_multiple is True? With tags, it's just: Code:
for tag in from_mi.tags: to_mi.tags.append(tag) Thanks. |
![]() |
![]() |
![]() |
#15 | ||
Grand Sorcerer
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 12,346
Karma: 8012652
Join Date: Jan 2010
Location: Notts, England
Device: Kobo Libra 2
|
Quote:
Set the value with db.set_custom(..., extra=series_index). You set the series and the series_index together. They cannot be set separately. Quote:
1) your code does not remove duplicates. The append() method adds the tag to the end of the list (array), with no check for duplicates. I assume that later you call db.set_tags(). That method checks for duplicate tags in the input list, which is why your code works. There are two ways to deal with duplicates, one with a set and one with 'in' check. The set code works because sets automatically remove duplicates, and would be something like: Code:
to_mi.tags = list(set(to_mi.tags) | set(from_mi.tags)) Code:
for tag in from_mi.tags: if tag not in to_mi.tags: to_mi.tags.append(tag) Code:
to_mi.tags.extend(from_mi.tags) Code:
# assume that label contains the column label. # id must be the id, not the index tags = db.get_custom(to_mi.id, label=label, index_is_id=True) tags.extend(db.get_custom(from_mi.id, label=label, index_is_id=True)) db.set_custom(to_mi.id, tags, label=label) |
||
![]() |
![]() |
![]() |
|
![]() |
||||
Thread | Thread Starter | Forum | Replies | Last Post |
Losing books/formats is not normal.-Chaley | theducks | Calibre | 7 | 10-02-2010 11:11 AM |
Suggestion: Selecting a user-defined Category should show all of the books in it | Daemon | Calibre | 6 | 08-23-2010 01:19 PM |
Jobs Queue, Merging, Metadata, I think that's it.... | rabidrobot | Calibre | 2 | 08-17-2010 07:31 PM |
User Defined Columns | jjansen | Calibre | 3 | 03-17-2010 05:33 PM |
User Defined Fonts | gr8npwrfl | Ectaco jetBook | 1 | 01-21-2010 08:35 AM |