base.py 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067
  1. """
  2. This packages includes all base classes to store basic information
  3. like id, name, mapset creation and modification time as well as sql
  4. serialization and de-serialization and the sql database interface.
  5. Usage:
  6. .. code-block:: python
  7. >>> import grass.temporal as tgis
  8. >>> tgis.init()
  9. >>> rbase = tgis.RasterBase(ident="soil@PERMANENT")
  10. >>> vbase = tgis.VectorBase(ident="soil:1@PERMANENT")
  11. >>> r3base = tgis.Raster3DBase(ident="soil@PERMANENT")
  12. >>> strdsbase = tgis.STRDSBase(ident="soil@PERMANENT")
  13. >>> stvdsbase = tgis.STVDSBase(ident="soil@PERMANENT")
  14. >>> str3dsbase = tgis.STR3DSBase(ident="soil@PERMANENT")
  15. (C) 2011-2013 by the GRASS Development Team
  16. This program is free software under the GNU General Public
  17. License (>=v2). Read the file COPYING that comes with GRASS
  18. for details.
  19. :author: Soeren Gebbert
  20. """
  21. from __future__ import print_function
  22. from datetime import datetime
  23. from .core import *
  24. ###############################################################################
  25. class DictSQLSerializer(object):
  26. def __init__(self):
  27. self.D = {}
  28. self.dbmi_paramstyle = get_tgis_dbmi_paramstyle()
  29. def serialize(self, type, table, where=None):
  30. """Convert the internal dictionary into a string of semicolon
  31. separated SQL statements The keys are the column names and
  32. the values are the row entries
  33. Usage:
  34. .. code-block:: python
  35. >>> init()
  36. >>> t = DictSQLSerializer()
  37. >>> t.D["id"] = "soil@PERMANENT"
  38. >>> t.D["name"] = "soil"
  39. >>> t.D["mapset"] = "PERMANENT"
  40. >>> t.D["creator"] = "soeren"
  41. >>> t.D["creation_time"] = datetime(2001,1,1)
  42. >>> t.D["modification_time"] = datetime(2001,1,1)
  43. >>> t.serialize(type="SELECT", table="raster_base")
  44. ('SELECT name , creator , creation_time , modification_time , mapset , id FROM raster_base ;\\n', ())
  45. >>> t.serialize(type="INSERT", table="raster_base")
  46. ('INSERT INTO raster_base ( name ,creator ,creation_time ,modification_time ,mapset ,id ) VALUES (? ,? ,? ,? ,? ,?) ;\\n', ('soil', 'soeren', datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2001, 1, 1, 0, 0), 'PERMANENT', 'soil@PERMANENT'))
  47. >>> t.serialize(type="UPDATE", table="raster_base")
  48. ('UPDATE raster_base SET name = ? ,creator = ? ,creation_time = ? ,modification_time = ? ,mapset = ? ,id = ? ;\\n', ('soil', 'soeren', datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2001, 1, 1, 0, 0), 'PERMANENT', 'soil@PERMANENT'))
  49. >>> t.serialize(type="UPDATE ALL", table="raster_base")
  50. ('UPDATE raster_base SET name = ? ,creator = ? ,creation_time = ? ,modification_time = ? ,mapset = ? ,id = ? ;\\n', ('soil', 'soeren', datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2001, 1, 1, 0, 0), 'PERMANENT', 'soil@PERMANENT'))
  51. :param type: must be SELECT. INSERT, UPDATE
  52. :param table: The name of the table to select, insert or update
  53. :param where: The optional where statement
  54. :return: a tuple containing the SQL string and the arguments
  55. """
  56. sql = ""
  57. args = []
  58. # Create ordered select statement
  59. if type == "SELECT":
  60. sql += 'SELECT '
  61. count = 0
  62. for key in self.D.keys():
  63. if count == 0:
  64. sql += ' %s ' % key
  65. else:
  66. sql += ' , %s ' % key
  67. count += 1
  68. sql += ' FROM ' + table + ' '
  69. if where:
  70. sql += where
  71. sql += ";\n"
  72. # Create insert statement
  73. if type == "INSERT":
  74. count = 0
  75. sql += 'INSERT INTO ' + table + ' ('
  76. for key in self.D.keys():
  77. if count == 0:
  78. sql += ' %s ' % key
  79. else:
  80. sql += ' ,%s ' % key
  81. count += 1
  82. count = 0
  83. sql += ') VALUES ('
  84. for key in self.D.keys():
  85. if count == 0:
  86. if self.dbmi_paramstyle == "qmark":
  87. sql += '?'
  88. else:
  89. sql += '%s'
  90. else:
  91. if self.dbmi_paramstyle == "qmark":
  92. sql += ' ,?'
  93. else:
  94. sql += ' ,%s'
  95. count += 1
  96. args.append(self.D[key])
  97. sql += ') '
  98. if where:
  99. sql += where
  100. sql += ";\n"
  101. # Create update statement for existing entries
  102. if type == "UPDATE":
  103. count = 0
  104. sql += 'UPDATE ' + table + ' SET '
  105. for key in self.D.keys():
  106. # Update only entries which are not None
  107. if self.D[key] is not None:
  108. if count == 0:
  109. if self.dbmi_paramstyle == "qmark":
  110. sql += ' %s = ? ' % key
  111. else:
  112. sql += ' %s ' % key
  113. sql += '= %s '
  114. else:
  115. if self.dbmi_paramstyle == "qmark":
  116. sql += ' ,%s = ? ' % key
  117. else:
  118. sql += ' ,%s ' % key
  119. sql += '= %s '
  120. count += 1
  121. args.append(self.D[key])
  122. if where:
  123. sql += where
  124. sql += ";\n"
  125. # Create update statement for all entries
  126. if type == "UPDATE ALL":
  127. count = 0
  128. sql += 'UPDATE ' + table + ' SET '
  129. for key in self.D.keys():
  130. if count == 0:
  131. if self.dbmi_paramstyle == "qmark":
  132. sql += ' %s = ? ' % key
  133. else:
  134. sql += ' %s ' % key
  135. sql += '= %s '
  136. else:
  137. if self.dbmi_paramstyle == "qmark":
  138. sql += ' ,%s = ? ' % key
  139. else:
  140. sql += ' ,%s ' % key
  141. sql += '= %s '
  142. count += 1
  143. args.append(self.D[key])
  144. if where:
  145. sql += where
  146. sql += ";\n"
  147. return sql, tuple(args)
  148. def deserialize(self, row):
  149. """Convert the content of the dbmi dictionary like row into the
  150. internal dictionary
  151. :param row: The dictionary like row to store in the internal dict
  152. """
  153. self.D = {}
  154. for key in row.keys():
  155. self.D[key] = row[key]
  156. def clear(self):
  157. """Initialize the internal storage"""
  158. self.D = {}
  159. def print_self(self):
  160. """Print the content of the internal dictionary to stdout
  161. """
  162. print(self.D)
  163. ###############################################################################
  164. class SQLDatabaseInterface(DictSQLSerializer):
  165. """This class represents the SQL database interface
  166. Functions to insert, select and update the internal
  167. structure of this class in the temporal database are implemented.
  168. This is the base class for raster, raster3d, vector and
  169. space time datasets data management classes:
  170. - Identification information (base)
  171. - Spatial extent
  172. - Temporal extent
  173. - Metadata
  174. Usage:
  175. .. code-block:: python
  176. >>> init()
  177. >>> t = SQLDatabaseInterface("raster", "soil@PERMANENT")
  178. >>> t.mapset = get_current_mapset()
  179. >>> t.D["name"] = "soil"
  180. >>> t.D["mapset"] = "PERMANENT"
  181. >>> t.D["creator"] = "soeren"
  182. >>> t.D["creation_time"] = datetime(2001,1,1)
  183. >>> t.get_delete_statement()
  184. "DELETE FROM raster WHERE id = 'soil@PERMANENT';\\n"
  185. >>> t.get_is_in_db_statement()
  186. "SELECT id FROM raster WHERE id = 'soil@PERMANENT';\\n"
  187. >>> t.get_select_statement()
  188. ("SELECT creation_time , mapset , name , creator FROM raster WHERE id = 'soil@PERMANENT';\\n", ())
  189. >>> t.get_select_statement_mogrified()
  190. "SELECT creation_time , mapset , name , creator FROM raster WHERE id = 'soil@PERMANENT';\\n"
  191. >>> t.get_insert_statement()
  192. ('INSERT INTO raster ( creation_time ,mapset ,name ,creator ) VALUES (? ,? ,? ,?) ;\\n', (datetime.datetime(2001, 1, 1, 0, 0), 'PERMANENT', 'soil', 'soeren'))
  193. >>> t.get_insert_statement_mogrified()
  194. "INSERT INTO raster ( creation_time ,mapset ,name ,creator ) VALUES ('2001-01-01 00:00:00' ,'PERMANENT' ,'soil' ,'soeren') ;\\n"
  195. >>> t.get_update_statement()
  196. ("UPDATE raster SET creation_time = ? ,mapset = ? ,name = ? ,creator = ? WHERE id = 'soil@PERMANENT';\\n", (datetime.datetime(2001, 1, 1, 0, 0), 'PERMANENT', 'soil', 'soeren'))
  197. >>> t.get_update_statement_mogrified()
  198. "UPDATE raster SET creation_time = '2001-01-01 00:00:00' ,mapset = 'PERMANENT' ,name = 'soil' ,creator = 'soeren' WHERE id = 'soil@PERMANENT';\\n"
  199. >>> t.get_update_all_statement()
  200. ("UPDATE raster SET creation_time = ? ,mapset = ? ,name = ? ,creator = ? WHERE id = 'soil@PERMANENT';\\n", (datetime.datetime(2001, 1, 1, 0, 0), 'PERMANENT', 'soil', 'soeren'))
  201. >>> t.get_update_all_statement_mogrified()
  202. "UPDATE raster SET creation_time = '2001-01-01 00:00:00' ,mapset = 'PERMANENT' ,name = 'soil' ,creator = 'soeren' WHERE id = 'soil@PERMANENT';\\n"
  203. """
  204. def __init__(self, table=None, ident=None):
  205. """Constructor of this class
  206. :param table: The name of the table
  207. :param ident: The identifier (primary key) of this
  208. object in the database table
  209. """
  210. DictSQLSerializer.__init__(self)
  211. self.table = table # Name of the table, set in the subclass
  212. self.ident = ident
  213. self.msgr = get_tgis_message_interface()
  214. if self.ident and self.ident.find("@") >= 0:
  215. self.mapset = self.ident.split("@""")[1]
  216. else:
  217. self.mapset = None
  218. def get_table_name(self):
  219. """Return the name of the table in which the internal
  220. data are inserted, updated or selected
  221. :return: The name of the table
  222. """
  223. return self.table
  224. def get_delete_statement(self):
  225. """Return the delete string
  226. :return: The DELETE string
  227. """
  228. return "DELETE FROM " + self.get_table_name() + \
  229. " WHERE id = \'" + str(self.ident) + "\';\n"
  230. def delete(self, dbif=None):
  231. """Delete the entry of this object from the temporal database
  232. :param dbif: The database interface to be used,
  233. if None a temporary connection will be established
  234. """
  235. sql = self.get_delete_statement()
  236. #print(sql)
  237. if dbif:
  238. dbif.execute(sql, mapset=self.mapset)
  239. else:
  240. dbif = SQLDatabaseInterfaceConnection()
  241. dbif.connect()
  242. dbif.execute(sql, mapset=self.mapset)
  243. dbif.close()
  244. def get_is_in_db_statement(self):
  245. """Return the selection string that checks if this object is registered in the
  246. temporal database
  247. :return: The SELECT string
  248. """
  249. return "SELECT id FROM " + self.get_table_name() + \
  250. " WHERE id = \'" + str(self.ident) + "\';\n"
  251. def is_in_db(self, dbif=None):
  252. """Check if this object is present in the temporal database
  253. :param dbif: The database interface to be used,
  254. if None a temporary connection will be established
  255. :return: True if this object is present in the temporal database,
  256. False otherwise
  257. """
  258. sql = self.get_is_in_db_statement()
  259. if dbif:
  260. dbif.execute(sql, mapset=self.mapset)
  261. row = dbif.fetchone(mapset=self.mapset)
  262. else:
  263. dbif = SQLDatabaseInterfaceConnection()
  264. dbif.connect()
  265. dbif.execute(sql, mapset=self.mapset)
  266. row = dbif.fetchone(mapset=self.mapset)
  267. dbif.close()
  268. # Nothing found
  269. if row is None:
  270. return False
  271. return True
  272. def get_select_statement(self):
  273. """Return the sql statement and the argument list in
  274. database specific style
  275. :return: The SELECT string
  276. """
  277. return self.serialize("SELECT", self.get_table_name(),
  278. "WHERE id = \'" + str(self.ident) + "\'")
  279. def get_select_statement_mogrified(self, dbif=None):
  280. """Return the select statement as mogrified string
  281. :param dbif: The database interface to be used,
  282. if None a temporary connection will be established
  283. :return: The SELECT string
  284. """
  285. if not dbif:
  286. dbif = SQLDatabaseInterfaceConnection()
  287. return dbif.mogrify_sql_statement(self.get_select_statement(),
  288. mapset=self.mapset)
  289. def select(self, dbif=None):
  290. """Select the content from the temporal database and store it
  291. in the internal dictionary structure
  292. :param dbif: The database interface to be used,
  293. if None a temporary connection will be established
  294. """
  295. sql, args = self.get_select_statement()
  296. #print(sql)
  297. #print(args)
  298. if dbif:
  299. if len(args) == 0:
  300. dbif.execute(sql, mapset=self.mapset)
  301. else:
  302. dbif.execute(sql, args, mapset=self.mapset)
  303. row = dbif.fetchone(mapset=self.mapset)
  304. else:
  305. dbif = SQLDatabaseInterfaceConnection()
  306. dbif.connect()
  307. if len(args) == 0:
  308. dbif.execute(sql, mapset=self.mapset)
  309. else:
  310. dbif.execute(sql, args, mapset=self.mapset)
  311. row = dbif.fetchone(mapset=self.mapset)
  312. dbif.close()
  313. # Nothing found
  314. if row is None:
  315. return False
  316. if len(row) > 0:
  317. self.deserialize(row)
  318. else:
  319. self.msgr.fatal(_("Object <%s> not found in the temporal database")
  320. % self.get_id())
  321. return True
  322. def get_insert_statement(self):
  323. """Return the sql statement and the argument
  324. list in database specific style
  325. :return: The INSERT string"""
  326. return self.serialize("INSERT", self.get_table_name())
  327. def get_insert_statement_mogrified(self, dbif=None):
  328. """Return the insert statement as mogrified string
  329. :param dbif: The database interface to be used,
  330. if None a temporary connection will be established
  331. :return: The INSERT string
  332. """
  333. if not dbif:
  334. dbif = SQLDatabaseInterfaceConnection()
  335. return dbif.mogrify_sql_statement(self.get_insert_statement(),
  336. mapset=self.mapset)
  337. def insert(self, dbif=None):
  338. """Serialize the content of this object and store it in the temporal
  339. database using the internal identifier
  340. :param dbif: The database interface to be used,
  341. if None a temporary connection will be established
  342. """
  343. sql, args = self.get_insert_statement()
  344. #print(sql)
  345. #print(args)
  346. if dbif:
  347. dbif.execute(sql, args, mapset=self.mapset)
  348. else:
  349. dbif = SQLDatabaseInterfaceConnection()
  350. dbif.connect()
  351. dbif.execute(sql, args, mapset=self.mapset)
  352. dbif.close()
  353. def get_update_statement(self, ident=None):
  354. """Return the sql statement and the argument list
  355. in database specific style
  356. :param ident: The identifier to be updated, useful for renaming
  357. :return: The UPDATE string
  358. """
  359. if ident:
  360. return self.serialize("UPDATE", self.get_table_name(),
  361. "WHERE id = \'" + str(ident) + "\'")
  362. else:
  363. return self.serialize("UPDATE", self.get_table_name(),
  364. "WHERE id = \'" + str(self.ident) + "\'")
  365. def get_update_statement_mogrified(self, dbif=None, ident=None):
  366. """Return the update statement as mogrified string
  367. :param dbif: The database interface to be used,
  368. if None a temporary connection will be established
  369. :param ident: The identifier to be updated, useful for renaming
  370. :return: The UPDATE string
  371. """
  372. if not dbif:
  373. dbif = SQLDatabaseInterfaceConnection()
  374. return dbif.mogrify_sql_statement(self.get_update_statement(ident),
  375. mapset=self.mapset)
  376. def update(self, dbif=None, ident=None):
  377. """Serialize the content of this object and update it in the temporal
  378. database using the internal identifier
  379. Only object entries which are exists (not None) are updated
  380. :param dbif: The database interface to be used,
  381. if None a temporary connection will be established
  382. :param ident: The identifier to be updated, useful for renaming
  383. """
  384. if self.ident is None:
  385. self.msgr.fatal(_("Missing identifer"))
  386. sql, args = self.get_update_statement(ident)
  387. #print(sql)
  388. #print(args)
  389. if dbif:
  390. dbif.execute(sql, args, mapset=self.mapset)
  391. else:
  392. dbif = SQLDatabaseInterfaceConnection()
  393. dbif.connect()
  394. dbif.execute(sql, args, mapset=self.mapset)
  395. dbif.close()
  396. def get_update_all_statement(self, ident=None):
  397. """Return the sql statement and the argument
  398. list in database specific style
  399. :param ident: The identifier to be updated, useful for renaming
  400. :return: The UPDATE string
  401. """
  402. if ident:
  403. return self.serialize("UPDATE ALL", self.get_table_name(),
  404. "WHERE id = \'" + str(ident) + "\'")
  405. else:
  406. return self.serialize("UPDATE ALL", self.get_table_name(),
  407. "WHERE id = \'" + str(self.ident) + "\'")
  408. def get_update_all_statement_mogrified(self, dbif=None, ident=None):
  409. """Return the update all statement as mogrified string
  410. :param dbif: The database interface to be used,
  411. if None a temporary connection will be established
  412. :param ident: The identifier to be updated, useful for renaming
  413. :return: The UPDATE string
  414. """
  415. if not dbif:
  416. dbif = SQLDatabaseInterfaceConnection()
  417. return dbif.mogrify_sql_statement(self.get_update_all_statement(ident),
  418. mapset=self.mapset)
  419. def update_all(self, dbif=None, ident=None):
  420. """Serialize the content of this object, including None objects,
  421. and update it in the temporal database using the internal identifier
  422. :param dbif: The database interface to be used,
  423. if None a temporary connection will be established
  424. :param ident: The identifier to be updated, useful for renaming
  425. """
  426. if self.ident is None:
  427. self.msgr.fatal(_("Missing identifer"))
  428. sql, args = self.get_update_all_statement(ident)
  429. #print(sql)
  430. #print(args)
  431. if dbif:
  432. dbif.execute(sql, args, mapset=self.mapset)
  433. else:
  434. dbif = SQLDatabaseInterfaceConnection()
  435. dbif.connect()
  436. dbif.execute(sql, args, mapset=self.mapset)
  437. dbif.close()
  438. ###############################################################################
  439. class DatasetBase(SQLDatabaseInterface):
  440. """This is the base class for all maps and spacetime datasets storing
  441. basic identification information
  442. Usage:
  443. .. code-block:: python
  444. >>> init()
  445. >>> t = DatasetBase("raster", "soil@PERMANENT", creator="soeren", ctime=datetime(2001,1,1), ttype="absolute")
  446. >>> t.id
  447. 'soil@PERMANENT'
  448. >>> t.name
  449. 'soil'
  450. >>> t.mapset
  451. 'PERMANENT'
  452. >>> t.creator
  453. 'soeren'
  454. >>> t.ctime
  455. datetime.datetime(2001, 1, 1, 0, 0)
  456. >>> t.ttype
  457. 'absolute'
  458. >>> t.print_info()
  459. +-------------------- Basic information -------------------------------------+
  460. | Id: ........................ soil@PERMANENT
  461. | Name: ...................... soil
  462. | Mapset: .................... PERMANENT
  463. | Creator: ................... soeren
  464. | Temporal type: ............. absolute
  465. | Creation time: ............. 2001-01-01 00:00:00
  466. >>> t.print_shell_info()
  467. id=soil@PERMANENT
  468. name=soil
  469. mapset=PERMANENT
  470. creator=soeren
  471. temporal_type=absolute
  472. creation_time=2001-01-01 00:00:00
  473. """
  474. def __init__(self, table=None, ident=None, name=None, mapset=None,
  475. creator=None, ctime=None, ttype=None):
  476. """Constructor
  477. :param table: The name of the temporal database table
  478. that should be used to store the values
  479. :param ident: The unique identifier must be a combination of
  480. the dataset name, layer name and the mapset
  481. "name@mapset" or "name:layer@mapset"
  482. used as as primary key in the temporal database
  483. :param name: The name of the map or dataset
  484. :param mapset: The name of the mapset
  485. :param creator: The name of the creator
  486. :param ctime: The creation datetime object
  487. :param ttype: The temporal type
  488. - "absolute" Identifier for absolute time
  489. - "relative" Identifier for relative time
  490. """
  491. SQLDatabaseInterface.__init__(self, table, ident)
  492. self.set_id(ident)
  493. if ident is not None and name is None and mapset is None:
  494. if ident.find("@") >= 0:
  495. name, mapset = ident.split("@")
  496. if name.find(":") >= 0:
  497. name, layer = ident.split(":")
  498. self.set_name(name)
  499. self.set_mapset(mapset)
  500. self.set_creator(creator)
  501. self.set_ctime(ctime)
  502. self.set_ttype(ttype)
  503. def set_id(self, ident):
  504. """Convenient method to set the unique identifier (primary key)
  505. :param ident: The unique identifier must be a combination
  506. of the dataset name, layer name and the mapset
  507. "name@mapset" or "name:layer@mapset"
  508. """
  509. self.ident = ident
  510. self.D["id"] = ident
  511. if ident is not None:
  512. if ident.find("@") >= 0:
  513. name, mapset = ident.split("@")
  514. self.set_mapset(mapset)
  515. self.set_name(name)
  516. else:
  517. self.msgr.fatal(_("Wrong identifier, the mapset is missing"))
  518. if name.find(":") >= 0:
  519. name, layer = ident.split(":")
  520. self.set_layer(layer)
  521. self.set_name(name)
  522. def set_name(self, name):
  523. """Set the name of the dataset
  524. :param name: The name of the dataset
  525. """
  526. self.D["name"] = name
  527. def set_mapset(self, mapset):
  528. """Set the mapset of the dataset
  529. :param mapset: The name of the mapset in which this dataset is stored
  530. """
  531. self.D["mapset"] = mapset
  532. def set_layer(self, layer):
  533. """Convenient method to set the layer of the map (part of primary key)
  534. Layer are supported for vector maps
  535. :param layer: The layer of the map
  536. """
  537. self.D["layer"] = layer
  538. def set_creator(self, creator):
  539. """Set the creator of the dataset
  540. :param creator: The name of the creator
  541. """
  542. self.D["creator"] = creator
  543. def set_ctime(self, ctime=None):
  544. """Set the creation time of the dataset,
  545. if nothing set the current time is used
  546. :param ctime: The current time of type datetime
  547. """
  548. if ctime is None:
  549. self.D["creation_time"] = datetime.today()
  550. else:
  551. self.D["creation_time"] = ctime
  552. def set_ttype(self, ttype):
  553. """Set the temporal type of the dataset: absolute or relative,
  554. if nothing set absolute time will assumed
  555. :param ttype: The temporal type of the dataset "absolute or relative"
  556. """
  557. if ttype is None or (ttype != "absolute" and ttype != "relative"):
  558. self.D["temporal_type"] = "absolute"
  559. else:
  560. self.D["temporal_type"] = ttype
  561. def get_id(self):
  562. """Convenient method to get the unique identifier (primary key)
  563. :return: None if not found
  564. """
  565. if "id" in self.D:
  566. return self.D["id"]
  567. else:
  568. return None
  569. def get_map_id(self):
  570. """Convenient method to get the unique map identifier
  571. without layer information
  572. :return: the name of the vector map as "name@mapset"
  573. or None in case the id was not set
  574. """
  575. if self.id:
  576. if self.id.find(":") >= 0:
  577. # Remove the layer identifier from the id
  578. return self.id.split("@")[0].split(":")[0] + "@" + \
  579. self.id.split("@")[1]
  580. else:
  581. return self.id
  582. else:
  583. return None
  584. def get_layer(self):
  585. """Convenient method to get the layer of the map (part of primary key)
  586. Layer are currently supported for vector maps
  587. :return: None if not found
  588. """
  589. if "layer" in self.D:
  590. return self.D["layer"]
  591. else:
  592. return None
  593. def get_name(self):
  594. """Get the name of the dataset
  595. :return: None if not found"""
  596. if "name" in self.D:
  597. return self.D["name"]
  598. else:
  599. return None
  600. def get_mapset(self):
  601. """Get the name of mapset of this dataset
  602. :return: None if not found"""
  603. if "mapset" in self.D:
  604. return self.D["mapset"]
  605. else:
  606. return None
  607. def get_creator(self):
  608. """Get the creator of the dataset
  609. :return: None if not found"""
  610. if "creator" in self.D:
  611. return self.D["creator"]
  612. else:
  613. return None
  614. def get_ctime(self):
  615. """Get the creation time of the dataset, datatype is datetime
  616. :return: None if not found"""
  617. if "creation_time" in self.D:
  618. return self.D["creation_time"]
  619. else:
  620. return None
  621. def get_ttype(self):
  622. """Get the temporal type of the map
  623. :return: None if not found"""
  624. if "temporal_type" in self.D:
  625. return self.D["temporal_type"]
  626. else:
  627. return None
  628. # Properties of this class
  629. id = property(fget=get_id, fset=set_id)
  630. map_id = property(fget=get_map_id, fset=None)
  631. name = property(fget=get_name, fset=set_name)
  632. mapset = property(fget=get_mapset, fset=set_mapset)
  633. ctime = property(fget=get_ctime, fset=set_ctime)
  634. ttype = property(fget=get_ttype, fset=set_ttype)
  635. creator = property(fget=get_creator, fset=set_creator)
  636. def print_info(self):
  637. """Print information about this class in human readable style"""
  638. # 0123456789012345678901234567890
  639. print( " +-------------------- Basic information -------------------------------------+")
  640. print( " | Id: ........................ " + str(self.get_id()))
  641. print(" | Name: ...................... " + str(self.get_name()))
  642. print(" | Mapset: .................... " + str(self.get_mapset()))
  643. if self.get_layer():
  644. print(" | Layer:...................... " + str(self.get_layer()))
  645. print(" | Creator: ................... " + str(self.get_creator()))
  646. print(" | Temporal type: ............. " + str(self.get_ttype()))
  647. print(" | Creation time: ............. " + str(self.get_ctime()))
  648. def print_shell_info(self):
  649. """Print information about this class in shell style"""
  650. print("id=" + str(self.get_id()))
  651. print("name=" + str(self.get_name()))
  652. print("mapset=" + str(self.get_mapset()))
  653. if self.get_layer():
  654. print("layer=" + str(self.get_layer()))
  655. print("creator=" + str(self.get_creator()))
  656. print("temporal_type=" + str(self.get_ttype()))
  657. print("creation_time=" + str(self.get_ctime()))
  658. ###############################################################################
  659. class RasterBase(DatasetBase):
  660. """Time stamped raster map base information class"""
  661. def __init__(self, ident=None, name=None, mapset=None, creator=None,
  662. creation_time=None, temporal_type=None):
  663. DatasetBase.__init__(self, "raster_base", ident, name, mapset,
  664. creator, creation_time, temporal_type)
  665. class Raster3DBase(DatasetBase):
  666. """Time stamped 3D raster map base information class"""
  667. def __init__(self, ident=None, name=None, mapset=None, creator=None,
  668. creation_time=None, temporal_type=None,):
  669. DatasetBase.__init__(self, "raster3d_base", ident, name,
  670. mapset, creator, creation_time,
  671. temporal_type)
  672. class VectorBase(DatasetBase):
  673. """Time stamped vector map base information class"""
  674. def __init__(self, ident=None, name=None, mapset=None, layer=None,
  675. creator=None, creation_time=None, temporal_type=None):
  676. DatasetBase.__init__(self, "vector_base", ident, name, mapset,
  677. creator, creation_time, temporal_type)
  678. self.set_id(ident)
  679. if ident is not None and name is None and mapset is None:
  680. if ident.find("@") >= 0:
  681. name, mapset = ident.split("@")
  682. if layer is None:
  683. if name.find(":") >= 0:
  684. name, layer = name.split(":")
  685. self.set_name(name)
  686. self.set_mapset(mapset)
  687. # Layer currently only in use by vector maps
  688. self.set_layer(layer)
  689. ###############################################################################
  690. class STDSBase(DatasetBase):
  691. """Base class for space time datasets
  692. This class adds the semantic type member variable to the dataset
  693. base class.
  694. Usage:
  695. .. code-block:: python
  696. >>> init()
  697. >>> t = STDSBase("stds", "soil@PERMANENT", semantic_type="average", creator="soeren", ctime=datetime(2001,1,1), ttype="absolute", mtime=datetime(2001,1,1))
  698. >>> t.semantic_type
  699. 'average'
  700. >>> t.print_info()
  701. +-------------------- Basic information -------------------------------------+
  702. | Id: ........................ soil@PERMANENT
  703. | Name: ...................... soil
  704. | Mapset: .................... PERMANENT
  705. | Creator: ................... soeren
  706. | Temporal type: ............. absolute
  707. | Creation time: ............. 2001-01-01 00:00:00
  708. | Modification time:.......... 2001-01-01 00:00:00
  709. | Semantic type:.............. average
  710. >>> t.print_shell_info()
  711. id=soil@PERMANENT
  712. name=soil
  713. mapset=PERMANENT
  714. creator=soeren
  715. temporal_type=absolute
  716. creation_time=2001-01-01 00:00:00
  717. modification_time=2001-01-01 00:00:00
  718. semantic_type=average
  719. """
  720. def __init__(self, table=None, ident=None, name=None, mapset=None,
  721. semantic_type=None, creator=None, ctime=None,
  722. ttype=None, mtime=None):
  723. DatasetBase.__init__(self, table, ident, name, mapset, creator,
  724. ctime, ttype)
  725. self.set_semantic_type(semantic_type)
  726. self.set_mtime(mtime)
  727. def set_semantic_type(self, semantic_type):
  728. """Set the semantic type of the space time dataset"""
  729. self.D["semantic_type"] = semantic_type
  730. def set_mtime(self, mtime=None):
  731. """Set the modification time of the space time dataset, if nothing set
  732. the current time is used
  733. """
  734. if mtime is None:
  735. self.D["modification_time"] = datetime.now()
  736. else:
  737. self.D["modification_time"] = mtime
  738. def get_semantic_type(self):
  739. """Get the semantic type of the space time dataset
  740. :return: None if not found
  741. """
  742. if "semantic_type" in self.D:
  743. return self.D["semantic_type"]
  744. else:
  745. return None
  746. def get_mtime(self):
  747. """Get the modification time of the space time dataset, datatype is
  748. datetime
  749. :return: None if not found
  750. """
  751. if self.D.has_key("modification_time"):
  752. return self.D["modification_time"]
  753. else:
  754. return None
  755. semantic_type = property(fget=get_semantic_type, fset=set_semantic_type)
  756. def print_info(self):
  757. """Print information about this class in human readable style"""
  758. DatasetBase.print_info(self)
  759. # 0123456789012345678901234567890
  760. print(" | Modification time:.......... " + str(self.get_mtime()))
  761. print(" | Semantic type:.............. " + str(
  762. self.get_semantic_type()))
  763. def print_shell_info(self):
  764. """Print information about this class in shell style"""
  765. DatasetBase.print_shell_info(self)
  766. print("modification_time=" + str(self.get_mtime()))
  767. print("semantic_type=" + str(self.get_semantic_type()))
  768. ###############################################################################
  769. class STRDSBase(STDSBase):
  770. """Space time raster dataset base information class"""
  771. def __init__(self, ident=None, name=None, mapset=None,
  772. semantic_type=None, creator=None, ctime=None,
  773. ttype=None):
  774. STDSBase.__init__(self, "strds_base", ident, name, mapset,
  775. semantic_type, creator, ctime,
  776. ttype)
  777. class STR3DSBase(STDSBase):
  778. """Space time 3D raster dataset base information class"""
  779. def __init__(self, ident=None, name=None, mapset=None,
  780. semantic_type=None, creator=None, ctime=None,
  781. ttype=None):
  782. STDSBase.__init__(self, "str3ds_base", ident, name, mapset,
  783. semantic_type, creator, ctime,
  784. ttype)
  785. class STVDSBase(STDSBase):
  786. """Space time vector dataset base information class"""
  787. def __init__(self, ident=None, name=None, mapset=None,
  788. semantic_type=None, creator=None, ctime=None,
  789. ttype=None):
  790. STDSBase.__init__(self, "stvds_base", ident, name, mapset,
  791. semantic_type, creator, ctime,
  792. ttype)
  793. ###############################################################################
  794. class AbstractSTDSRegister(SQLDatabaseInterface):
  795. """This is the base class for all maps to store the space time datasets
  796. as comma separated string in which they are registered
  797. Usage:
  798. .. code-block:: python
  799. >>> init()
  800. >>> t = AbstractSTDSRegister("raster", "soil@PERMANENT", "A@P,B@P,C@P")
  801. >>> t.id
  802. 'soil@PERMANENT'
  803. >>> t.registered_stds
  804. 'A@P,B@P,C@P'
  805. """
  806. def __init__(self, table=None, ident=None, registered_stds=None):
  807. """Constructor
  808. :param table: The name of the temporal database table
  809. that should be used to store the values
  810. :param ident: The unique identifier must be a combination of
  811. the dataset name, layer name and the mapset
  812. "name@mapset" or "name:layer@mapset"
  813. used as as primary key in the temporal database
  814. :param stds: A comma separted list of space time dataset ids
  815. """
  816. SQLDatabaseInterface.__init__(self, table, ident)
  817. self.set_id(ident)
  818. self.set_registered_stds(registered_stds)
  819. def set_id(self, ident):
  820. """Convenient method to set the unique identifier (primary key)
  821. :param ident: The unique identifier must be a combination
  822. of the dataset name, layer name and the mapset
  823. "name@mapset" or "name:layer@mapset"
  824. """
  825. self.ident = ident
  826. self.D["id"] = ident
  827. def set_registered_stds(self, registered_stds):
  828. """Get the comma separated list of space time datasets ids
  829. in which this map is registered
  830. :param registered_stds: A comma separated list of space time
  831. dataset ids in which this map is registered
  832. """
  833. self.D["registered_stds"] = registered_stds
  834. def get_id(self):
  835. """Convenient method to get the unique identifier (primary key)
  836. :return: None if not found
  837. """
  838. if "id" in self.D:
  839. return self.D["id"]
  840. else:
  841. return None
  842. def get_registered_stds(self):
  843. """Get the comma separated list of space time datasets ids
  844. in which this map is registered
  845. :return: None if not found
  846. """
  847. if "registered_stds" in self.D:
  848. return self.D["registered_stds"]
  849. else:
  850. return None
  851. # Properties of this class
  852. id = property(fget=get_id, fset=set_id)
  853. registered_stds = property(fget=get_registered_stds,
  854. fset=set_registered_stds)
  855. ###############################################################################
  856. class RasterSTDSRegister(AbstractSTDSRegister):
  857. """Time stamped raster map base information class"""
  858. def __init__(self, ident=None, registered_stds=None):
  859. AbstractSTDSRegister.__init__(self, "raster_stds_register", ident,
  860. registered_stds)
  861. class Raster3DSTDSRegister(AbstractSTDSRegister):
  862. """Time stamped 3D raster map base information class"""
  863. def __init__(self, ident=None, registered_stds=None):
  864. AbstractSTDSRegister.__init__(self, "raster3d_stds_register", ident,
  865. registered_stds)
  866. class VectorSTDSRegister(AbstractSTDSRegister):
  867. """Time stamped vector map base information class"""
  868. def __init__(self, ident=None, registered_stds=None):
  869. AbstractSTDSRegister.__init__(self, "vector_stds_register", ident,
  870. registered_stds)
  871. ###############################################################################
  872. if __name__ == "__main__":
  873. import doctest
  874. doctest.testmod()