author | ymh <ymh.work@gmail.com> |
Tue, 26 Jun 2018 16:22:54 +0200 | |
changeset 21 | 631f70f55fed |
parent 5 | cfd40849d24c |
permissions | -rw-r--r-- |
5
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
1 |
# -*- coding: UTF-8 -*- |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
2 |
from django.core.management.base import BaseCommand, CommandError |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
3 |
from django.core.management import call_command |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
4 |
from django.conf import settings |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
5 |
from iconolab.models import Collection, Item, ItemMetadata, MetaCategory |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
6 |
from sorl.thumbnail import get_thumbnail |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
7 |
import os, csv, pprint, re, json, shutil |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
8 |
|
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
9 |
class Command(BaseCommand): |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
10 |
help = "import images from a directory into the media folder and creates item and image objects" |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
11 |
|
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
12 |
def add_arguments(self, parser): |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
13 |
parser.add_argument("csv_path") |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
14 |
parser.add_argument( |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
15 |
'--encoding', |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
16 |
dest='encoding', |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
17 |
default='utf-8', |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
18 |
help='CSV file encoding' |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
19 |
|
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
20 |
) |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
21 |
parser.add_argument( |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
22 |
'--collection-id', |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
23 |
dest='collection_id', |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
24 |
default=False, |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
25 |
help='insert extracted data into the specified collection instead of trying to load a collection fixture', |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
26 |
) |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
27 |
parser.add_argument( |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
28 |
'--delimiter', |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
29 |
dest='csv_delimiter', |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
30 |
default=';', |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
31 |
help='csv file delimiter' |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
32 |
) |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
33 |
|
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
34 |
def handle(self, *args, **options): |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
35 |
try: |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
36 |
# Check we have a collection to store data into: |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
37 |
source_dir = os.path.dirname(os.path.realpath(options.get("csv_path"))) |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
38 |
print("# Checking collection args") |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
39 |
if options.get("collection_id"): |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
40 |
print("## Finding collection with id "+options.get("collection_id")) |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
41 |
try: |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
42 |
collection = Collection.objects.get(pk=options.get("collection_id")) |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
43 |
except Collection.DoesNotExist: |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
44 |
raise ValueError("!!! Collection with primary key "+options.get("collection_id")+" was not found, aborting !!!") |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
45 |
else: |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
46 |
raise ValueError("!!! No collection id, aborting because we don't know which collection to update. !!!") |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
47 |
|
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
48 |
# We read the csv |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
49 |
delimiter = options.get('csv_delimiter') |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
50 |
if delimiter == "#9": |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
51 |
delimiter = chr(9) |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
52 |
if delimiter == "#29": |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
53 |
delimiter = chr(29) |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
54 |
if delimiter == "#30": |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
55 |
delimiter = chr(30) |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
56 |
if delimiter == "#31": |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
57 |
delimiter = chr(31) |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
58 |
csvreader = csv.DictReader(open(options.get("csv_path"), encoding=options.get("encoding")), delimiter=delimiter) |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
59 |
print("# Extracting data from csv file and storing it in standardized format") |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
60 |
# We store data using the Jocondelab keys, as defined in settings.IMPORT_FIELDS_DICT |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
61 |
cleaned_csv_data=[] |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
62 |
for row in csvreader: |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
63 |
cleaned_row_data = {} |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
64 |
for key in settings.IMPORT_FIELDS_DICT.keys(): |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
65 |
cleaned_row_data[key] = "" |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
66 |
for row_key in row.keys(): |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
67 |
if row_key in settings.IMPORT_FIELDS_DICT[key]: |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
68 |
# Handling the multiple natural keys exports nonsense |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
69 |
if key == "REF": |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
70 |
natural_key_number, _, _ = row[row_key].partition(";") |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
71 |
cleaned_row_data[key] = natural_key_number.rstrip() |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
72 |
else: |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
73 |
cleaned_row_data[key] = row[row_key] |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
74 |
break |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
75 |
cleaned_csv_data.append(cleaned_row_data) |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
76 |
# Listing image files in csv directory |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
77 |
filtered_csv_data = [] |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
78 |
# Now we trim the cleaned_csv_data dict to keep only entries that already exist in the database in Item form (using the natural key) |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
79 |
for item in cleaned_csv_data: |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
80 |
if item.get("REF", "") and ItemMetadata.objects.filter(item__collection = collection, natural_key=item.get("REF")).exists(): |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
81 |
filtered_csv_data.append(item) |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
82 |
print("## found " + str(len(filtered_csv_data))+" items to update") |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
83 |
print("# Updating data from Iconolab") |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
84 |
for item in filtered_csv_data: |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
85 |
item_metadatas = ItemMetadata.objects.filter(item__collection = collection, natural_key=item.get("REF")).first() |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
86 |
if not item["REF"]: |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
87 |
print("#### No Natural key, skipping") |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
88 |
continue |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
89 |
item_authors = item["AUTR"] |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
90 |
item_school = item["ECOLE"] |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
91 |
item_designation = "" |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
92 |
if item.get("TITR", ""): |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
93 |
item_designation = item["TITR"] |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
94 |
elif item.get("DENO", ""): |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
95 |
item_designation = item["DENO"] |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
96 |
elif item.get("APPL", ""): |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
97 |
item_designation = item["APPL"] |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
98 |
item_datation = "" |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
99 |
if item.get("PERI", ""): |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
100 |
item_datation = item["PERI"] |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
101 |
elif item.get("MILL", ""): |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
102 |
item_datation = item["MILL"] |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
103 |
elif item.get("EPOQ", ""): |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
104 |
item_datation = item["EPOQ"] |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
105 |
item_technics = item["TECH"] |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
106 |
item_field = item["DOM"] |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
107 |
item_measurements = item["DIMS"] |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
108 |
item_create_or_usage_location = item["LIEUX"] |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
109 |
item_discovery_context = item["DECV"] |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
110 |
item_conservation_location = item["LOCA"] |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
111 |
item_photo_credits = item["PHOT"] |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
112 |
item_inventory_number = item["INV"] |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
113 |
item_joconde_ref = item["REF"] |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
114 |
# Updating metadatas |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
115 |
|
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
116 |
new_metadata = { |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
117 |
"authors" : item_authors, |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
118 |
"school" : item_school, |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
119 |
"designation" : item_designation, |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
120 |
"field" : item_field, |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
121 |
"datation" : item_datation, |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
122 |
"technics" : item_technics, |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
123 |
"measurements" : item_measurements, |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
124 |
"create_or_usage_location" : item_create_or_usage_location, |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
125 |
"discovery_context" : item_discovery_context, |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
126 |
"conservation_location" : item_conservation_location, |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
127 |
"photo_credits" : item_photo_credits, |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
128 |
"inventory_number" : item_inventory_number, |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
129 |
"joconde_ref" : item_joconde_ref |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
130 |
} |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
131 |
|
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
132 |
item_metadatas.metadata = json.dumps(new_metadata) |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
133 |
item_metadatas.natural_key = item_joconde_ref |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
134 |
item_metadatas.save() |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
135 |
print('### Generating thumbnails for item '+item['REF']) |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
136 |
for image in item_metadatas.item.images.all(): |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
137 |
for size in settings.PREGENERATE_THUMBNAILS_SIZES: |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
138 |
print('#### Thumbnail for size '+size) |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
139 |
get_thumbnail(image.media, size, crop=False) |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
140 |
print("# All done!") |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
141 |
except FileNotFoundError: |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
142 |
print("!!! File "+options.get("csv_path")+" does not exist. !!!") |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
143 |
except ValueError as e: |
cfd40849d24c
Turning iconolab-mcc into App to add specific import commands
Riwad Salim
parents:
diff
changeset
|
144 |
print(str(e)) |