Package Bio :: Package motifs :: Package jaspar :: Module db
[hide private]
[frames] | no frames]

Source Code for Module Bio.motifs.jaspar.db

  1  # Copyright 2013 by David Arenillas and Anthony Mathelier. All rights reserved. 
  2  # This code is part of the Biopython distribution and governed by its 
  3  # license. Please see the LICENSE file that should have been included 
  4  # as part of this package. 
  5  """Provides read access to a JASPAR5 formatted database. 
  6   
  7  This modules requires MySQLdb to be installed. 
  8   
  9  Example, substitute the your database credentials as 
 10  appropriate: 
 11   
 12      >>> from Bio.motifs.jaspar.db import JASPAR5 
 13      >>> 
 14      >>> JASPAR_DB_HOST = "hostname.example.org" 
 15      >>> JASPAR_DB_NAME = "JASPAR_2013" 
 16      >>> JASPAR_DB_USER = "guest" 
 17      >>> JASPAR_DB_PASS = "guest" 
 18      >>> 
 19      >>> DFLT_COLLECTION = 'CORE' 
 20      >>> jdb = JASPAR5( 
 21      ...     host=JASPAR_DB_HOST, 
 22      ...     name=JASPAR_DB_NAME, 
 23      ...     user=JASPAR_DB_USER, 
 24      ...     password=JASPAR_DB_PASS 
 25      ... ) 
 26      >>> 
 27      >>> 
 28      >>> ets1 = jdb.fetch_motif_by_id('MA0098') 
 29      >>> print(ets1) 
 30      TF name ETS1 
 31      Matrix ID   MA0098.1 
 32      Collection  CORE 
 33      TF class    Winged Helix-Turn-Helix 
 34      TF family   Ets 
 35      Species 9606 
 36      Taxonomic group vertebrates 
 37      Accession   ['CAG47050'] 
 38      Data type used  SELEX 
 39      Medline 1542566 
 40      PAZAR ID    TF0000070 
 41      Comments    - 
 42      Matrix: 
 43              0      1      2      3      4      5 
 44      A:   4.00  17.00   0.00   0.00   0.00   5.00 
 45      C:  16.00   0.00   1.00  39.00  39.00   3.00 
 46      G:   4.00   0.00   0.00   1.00   0.00  17.00 
 47      T:  16.00  23.00  39.00   0.00   1.00  15.00 
 48   
 49   
 50      >>> 
 51      >>> motifs = jdb.fetch_motifs( 
 52      ...     collection = 'CORE', 
 53      ...     tax_group = ['vertebrates', 'insects'], 
 54      ...     tf_class = 'Winged Helix-Turn-Helix', 
 55      ...     tf_family = ['Forkhead', 'Ets'], 
 56      ...     min_ic = 12 
 57      ... ) 
 58      >>> 
 59      >>> for motif in motifs: 
 60      ...     pass # do something with the motif 
 61   
 62  """ 
 63   
 64  from __future__ import print_function 
 65   
 66  from Bio import MissingPythonDependencyError 
 67   
 68  try: 
 69      import MySQLdb as mdb 
 70  except: 
 71      raise MissingPythonDependencyError("Install MySQLdb if you want to use " 
 72                                         "Bio.motifs.jaspar.db") 
 73   
 74  from Bio.Alphabet.IUPAC import unambiguous_dna as dna 
 75   
 76  from Bio.motifs import jaspar, matrix 
 77  from warnings import warn 
 78   
 79  __docformat__ = "restructuredtext en" 
 80   
 81  JASPAR_DFLT_COLLECTION = 'CORE' 
 82   
 83   
84 -class JASPAR5(object):
85 """ 86 Class representing a JASPAR5 DB. The methods within are loosely based 87 on the perl TFBS::DB::JASPAR5 module. 88 89 Note: We will only implement reading of JASPAR motifs from the DB. 90 Unlike the perl module, we will not attempt to implement any methods to 91 store JASPAR motifs or create a new DB at this time. 92 93 """ 94
95 - def __init__(self, host=None, name=None, user=None, password=None):
96 """ 97 Construct a JASPAR5 instance and connect to specified DB 98 99 Arguments: 100 host - host name of the the JASPAR DB server 101 name - name of the JASPAR database 102 user - user name to connect to the JASPAR DB 103 password - JASPAR DB password 104 105 """ 106 107 self.name = name 108 self.host = host 109 self.user = user 110 self.password = password 111 112 self.dbh = mdb.connect(host, user, password, name)
113
114 - def __str__(self):
115 """ 116 Return a string represention of the JASPAR5 DB connection. 117 118 """ 119 120 text = "%s\@%s:%s" % (self.user, self.host, self.name) 121 122 return text
123
124 - def fetch_motif_by_id(self, id):
125 """ 126 Fetch a single JASPAR motif from the DB by it's JASPAR matrix ID 127 (e.g. 'MA0001.1'). 128 129 Arguments: 130 131 - id - JASPAR matrix ID. This may be a fully specified ID including the 132 version number (e.g. MA0049.2) or just the base ID (e.g. MA0049). 133 If only a base ID is provided, the latest version is returned. 134 135 Returns: 136 137 - A Bio.motifs.jaspar.Motif object 138 139 **NOTE:** The perl TFBS module allows you to specify the type of matrix to 140 return (PFM, PWM, ICM) but matrices are always stored in JASAPR as 141 PFMs so this does not really belong here. Once a PFM is fetched the 142 pwm() and pssm() methods can be called to return the normalized and 143 log-odds matrices. 144 145 """ 146 147 # separate stable ID and version number 148 (base_id, version) = jaspar.split_jaspar_id(id) 149 if not version: 150 # if ID contains no version portion, fetch latest version by default 151 version = self._fetch_latest_version(base_id) 152 153 # fetch internal JASPAR matrix ID - also a check for validity 154 int_id = self._fetch_internal_id(base_id, version) 155 156 # fetch JASPAR motif using internal ID 157 motif = self._fetch_motif_by_internal_id(int_id) 158 159 return motif
160
161 - def fetch_motifs_by_name(self, name):
162 """ 163 Fetch a list of JASPAR motifs from a JASPAR DB by the given TF name(s). 164 165 Arguments: 166 name - a single name or list of names 167 Returns: 168 A list of Bio.motifs.Motif.japar objects 169 170 Notes: 171 Names are not guaranteed to be unique. There may be more than one 172 motif with the same name. Therefore even if name specifies a single 173 name, a list of motifs is returned. This just calls 174 self.fetch_motifs(collection = None, tf_name = name). 175 176 This behaviour is different from the TFBS perl module's 177 get_Matrix_by_name() method which always returns a single matrix, 178 issuing a warning message and returning the first matrix retrieved 179 in the case where multiple matrices have the same name. 180 181 """ 182 183 return self.fetch_motifs(collection=None, tf_name=name)
184
185 - def fetch_motifs( 186 self, collection=JASPAR_DFLT_COLLECTION, tf_name=None, tf_class=None, 187 tf_family=None, matrix_id=None, tax_group=None, species=None, 188 pazar_id=None, data_type=None, medline=None, min_ic=0, min_length=0, 189 min_sites=0, all=False, all_versions=False 190 ):
191 """ 192 Fetch a jaspar.Record (list) of motifs based on the provided selection 193 criteria. 194 195 Arguments:: 196 197 Except where obvious, all selection criteria arguments may be specified 198 as a single value or a list of values. Motifs must meet ALL the 199 specified selection criteria to be returned with the precedent 200 exceptions noted below. 201 202 all - Takes precedent of all other selection criteria. 203 Every motif is returned. If 'all_versions' is also 204 specified, all versions of every motif are returned, 205 otherwise just the latest version of every motif is 206 returned. 207 matrix_id - Takes precedence over all other selection criteria except 208 'all'. Only motifs with the given JASPAR matrix ID(s) 209 are returned. A matrix ID may be specified as just a base 210 ID or full JASPAR IDs including version number. If only a 211 base ID is provided for specific motif(s), then just the 212 latest version of those motif(s) are returned unless 213 'all_versions' is also specified. 214 collection - Only motifs from the specified JASPAR collection(s) 215 are returned. NOTE - if not specified, the collection 216 defaults to CORE for all other selection criteria except 217 'all' and 'matrix_id'. To apply the other selection 218 criteria across all JASPAR collections, explicitly set 219 collection=None. 220 tf_name - Only motifs with the given name(s) are returned. 221 tf_class - Only motifs of the given TF class(es) are returned. 222 tf_family - Only motifs from the given TF families are returned. 223 tax_group - Only motifs belonging to the given taxonomic supergroups 224 are returned (e.g. 'vertebrates', 'insects', 'nematodes' 225 etc.) 226 species - Only motifs derived from the given species are returned. 227 Species are specified as taxonomy IDs. 228 data_type - Only motifs generated with the given data type (e.g. 229 ('ChIP-seq', 'PBM', 'SELEX' etc.) are returned. NOTE - 230 must match exactly as stored in the database. 231 pazar_id - Only motifs with the given PAZAR TF ID are returned. 232 medline - Only motifs with the given medline (PubmMed IDs) are 233 returned. 234 min_ic - Only motifs whose profile matrices have at least this 235 information content (specificty) are returned. 236 min_length - Only motifs whose profiles are of at least this length 237 are returned. 238 min_sites - Only motifs compiled from at least these many binding 239 sites are returned. 240 all_versions- Unless specified, just the latest version of motifs 241 determined by the other selection criteria are returned 242 otherwise all versions of the selected motifs are 243 returned. 244 245 Returns: 246 247 - A Bio.motifs.jaspar.Record (list) of motifs. 248 249 """ 250 251 # Fetch the internal IDs of the motifs using the criteria provided 252 int_ids = self._fetch_internal_id_list( 253 collection=collection, 254 tf_name=tf_name, 255 tf_class=tf_class, 256 tf_family=tf_family, 257 matrix_id=matrix_id, 258 tax_group=tax_group, 259 species=species, 260 pazar_id=pazar_id, 261 data_type=data_type, 262 medline=medline, 263 all=all, 264 all_versions=all_versions 265 ) 266 267 record = jaspar.Record() 268 269 """ 270 Now further filter motifs returned above based on any specified 271 matrix specific criteria. 272 """ 273 for int_id in int_ids: 274 motif = self._fetch_motif_by_internal_id(int_id) 275 276 # Filter motifs to those with matrix IC greater than min_ic 277 if min_ic: 278 if motif.pssm.mean() < min_ic: 279 continue 280 281 # Filter motifs to those with minimum length of min_length 282 if min_length: 283 if motif.length < min_length: 284 continue 285 286 # XXX We could also supply a max_length filter. 287 288 """ 289 Filter motifs to those composed of at least this many sites. 290 The perl TFBS module assumes column sums may be different but 291 this should be strictly enforced here we will ignore this and 292 just use the first column sum. 293 """ 294 if min_sites: 295 num_sites = sum( 296 [motif.counts[nt][0] for nt in motif.alphabet.letters] 297 ) 298 if num_sites < min_sites: 299 continue 300 301 record.append(motif) 302 303 return record
304
305 - def _fetch_latest_version(self, base_id):
306 """ 307 Get the latest version number for the given base_id, 308 309 """ 310 311 sql = "select VERSION from MATRIX where BASE_id = '%s' order by VERSION desc limit 1" % base_id 312 313 cur = self.dbh.cursor() 314 cur.execute(sql) 315 316 latest = cur.fetchone()[0] 317 318 return latest
319
320 - def _fetch_internal_id(self, base_id, version):
321 """ 322 Fetch the internal id for a base id + version. Also checks if this 323 combo exists or not 324 325 """ 326 327 sql = "select id from MATRIX where BASE_id = '%s' and VERSION = '%s'" % (base_id, version) 328 329 cur = self.dbh.cursor() 330 cur.execute(sql) 331 332 int_id = cur.fetchone()[0] 333 334 return int_id
335
336 - def _fetch_motif_by_internal_id(self, int_id):
337 # fetch basic motif information 338 sql = "select BASE_ID, VERSION, COLLECTION, NAME from MATRIX where id = %d" % int_id 339 340 cur = self.dbh.cursor() 341 cur.execute(sql) 342 343 row = cur.fetchone() 344 345 base_id = row[0] 346 version = row[1] 347 collection = row[2] 348 name = row[3] 349 350 matrix_id = "".join([base_id, '.', str(version)]) 351 352 # fetch the counts matrix 353 counts = self._fetch_counts_matrix(int_id) 354 355 # Create new JASPAR motif 356 motif = jaspar.Motif( 357 matrix_id, name, collection=collection, counts=counts 358 ) 359 360 # fetch species 361 sql = "select TAX_ID from MATRIX_SPECIES where id = %d" % int_id 362 cur.execute(sql) 363 tax_ids = [] 364 rows = cur.fetchall() 365 for row in rows: 366 tax_ids.append(row[0]) 367 368 motif.species = tax_ids 369 370 # fetch protein accession numbers 371 sql = "select ACC FROM MATRIX_PROTEIN where id = %d" % int_id 372 cur.execute(sql) 373 accs = [] 374 rows = cur.fetchall() 375 for row in rows: 376 accs.append(row[0]) 377 378 motif.acc = accs 379 380 # fetch remaining annotation as tags from the ANNOTATION table 381 sql = "select TAG, VAL from MATRIX_ANNOTATION where id = %d" % int_id 382 cur.execute(sql) 383 rows = cur.fetchall() 384 for row in rows: 385 attr = row[0] 386 val = row[1] 387 if attr == 'class': 388 motif.tf_class = val 389 elif attr == 'family': 390 motif.tf_family = val 391 elif attr == 'tax_group': 392 motif.tax_group = val 393 elif attr == 'type': 394 motif.data_type = val 395 elif attr == 'pazar_tf_id': 396 motif.pazar_id = val 397 elif attr == 'medline': 398 motif.medline = val 399 elif attr == 'comment': 400 motif.comment = val 401 else: 402 """ 403 TODO If we were to implement additional abitrary tags 404 motif.tag(attr, val) 405 """ 406 pass 407 408 return motif
409
410 - def _fetch_counts_matrix(self, int_id):
411 """ 412 Fetch the counts matrix from the JASPAR DB by the internal ID 413 414 Returns a Bio.motifs.matrix.GenericPositionMatrix 415 416 """ 417 counts = {} 418 cur = self.dbh.cursor() 419 420 for base in dna.letters: 421 base_counts = [] 422 423 cur.execute("select val from MATRIX_DATA where ID = %s and row = %s order by col", (int_id, base)) 424 425 rows = cur.fetchall() 426 for row in rows: 427 base_counts.append(row[0]) 428 429 counts[base] = [float(x) for x in base_counts] 430 431 return matrix.GenericPositionMatrix(dna, counts)
432
433 - def _fetch_internal_id_list( 434 self, collection=JASPAR_DFLT_COLLECTION, tf_name=None, tf_class=None, 435 tf_family=None, matrix_id=None, tax_group=None, species=None, 436 pazar_id=None, data_type=None, medline=None, all=False, 437 all_versions=False 438 ):
439 """ 440 Fetch a list of internal JASPAR motif IDs based on various passed 441 parameters which may then be used to fetch the rest of the motif data. 442 443 Caller: 444 fetch_motifs() 445 446 Arguments: 447 See arguments sections of fetch_motifs() 448 449 Returns: 450 A list of internal JASPAR motif IDs which match the given 451 selection criteria arguments. 452 453 454 Build an SQL query based on the selection arguments provided. 455 456 1: First add table joins and sub-clauses for criteria corresponding to 457 named fields from the MATRIX and MATRIX_SPECIES tables such as 458 collection, matrix ID, name, species etc. 459 460 2: Then add joins/sub-clauses for tag/value parameters from the 461 MATRIX_ANNOTATION table. 462 463 For the surviving matrices, the responsibility to do matrix-based 464 feature filtering such as ic, number of sites etc, fall on the 465 calling fetch_motifs() method. 466 467 """ 468 469 int_ids = [] 470 471 cur = self.dbh.cursor() 472 473 """ 474 Special case 1: fetch ALL motifs. Highest priority. 475 Ignore all other selection arguments. 476 """ 477 if all: 478 cur.execute("select ID from MATRIX") 479 rows = cur.fetchall() 480 481 for row in rows: 482 int_ids.append(row[0]) 483 484 return int_ids 485 486 """ 487 Special case 2: fetch specific motifs by their JASPAR IDs. This 488 has higher priority than any other except the above 'all' case. 489 Ignore all other selection arguments. 490 """ 491 if matrix_id: 492 """ 493 These might be either stable IDs or stable_ID.version. 494 If just stable ID and if all_versions == 1, return all versions, 495 otherwise just the latest 496 """ 497 if all_versions: 498 for id in matrix_id: 499 # ignore vesion here, this is a stupidity filter 500 (base_id, version) = jaspar.split_jaspar_id(id) 501 cur.execute( 502 "select ID from MATRIX where BASE_ID = %s", base_id 503 ) 504 505 rows = cur.fetchall() 506 for row in rows: 507 int_ids.append(row[0]) 508 else: 509 # only the lastest version, or the requested version 510 for id in matrix_id: 511 (base_id, version) = jaspar.split_jaspar_id(id) 512 513 if not version: 514 version = self._fetch_latest_version(base_id) 515 516 int_id = self._fetch_internal_id(base_id, version) 517 518 if int_id: 519 int_ids.append(int_id) 520 521 return int_ids 522 523 tables = ["MATRIX m"] 524 where_clauses = [] 525 526 # Select by MATRIX.COLLECTION 527 if collection: 528 if isinstance(collection, list): 529 # Multiple collections passed in as a list 530 clause = "m.COLLECTION in ('" 531 clause = "".join([clause, "','".join(collection)]) 532 clause = "".join([clause, "')"]) 533 else: 534 # A single collection - typical usage 535 clause = "m.COLLECTION = '%s'" % collection 536 537 where_clauses.append(clause) 538 539 # Select by MATRIX.NAME 540 if tf_name: 541 if isinstance(tf_name, list): 542 # Multiple names passed in as a list 543 clause = "m.NAME in ('" 544 clause = "".join([clause, "','".join(tf_name)]) 545 clause = "".join([clause, "')"]) 546 else: 547 # A single name 548 clause = "m.NAME = '%s'" % tf_name 549 550 where_clauses.append(clause) 551 552 # Select by MATRIX_SPECIES.TAX_ID 553 if species: 554 tables.append("MATRIX_SPECIES ms") 555 where_clauses.append("m.ID = ms.ID") 556 557 """ 558 NOTE: species are numeric taxonomy IDs but stored as varchars 559 in the DB. 560 """ 561 if isinstance(species, list): 562 # Multiple tax IDs passed in as a list 563 clause = "ms.TAX_ID in ('" 564 clause = "".join([clause, "','".join(str(s) for s in species)]) 565 clause = "".join([clause, "')"]) 566 else: 567 # A single tax ID 568 clause = "ms.TAX_ID = '%s'" % str(species) 569 570 where_clauses.append(clause) 571 572 """ 573 Tag based selection from MATRIX_ANNOTATION 574 Differs from perl TFBS module in that the matrix class explicitly 575 has a tag attribute corresponding to the tags in the database. This 576 provides tremendous flexibility in adding new tags to the DB and 577 being able to select based on those tags with out adding new code. 578 In the JASPAR Motif class we have elected to use specific attributes 579 for the most commonly used tags and here correspondingly only allow 580 selection on these attributes. 581 582 The attributes corresponding to the tags for which selection is 583 provided are: 584 585 Attribute Tag 586 tf_class class 587 tf_family family 588 pazar_id pazar_tf_id 589 medline medline 590 data_type type 591 tax_group tax_group 592 """ 593 594 # Select by TF class(es) (MATRIX_ANNOTATION.TAG="class") 595 if tf_class: 596 tables.append("MATRIX_ANNOTATION ma1") 597 where_clauses.append("m.ID = ma1.ID") 598 599 clause = "ma1.TAG = 'class'" 600 if isinstance(tf_class, list): 601 # A list of TF classes 602 clause = "".join([clause, " and ma1.VAL in ('"]) 603 clause = "".join([clause, "','".join(tf_class)]) 604 clause = "".join([clause, "')"]) 605 else: 606 # A single TF class 607 clause = "".join([clause, " and ma1.VAL = '%s' " % tf_class]) 608 609 where_clauses.append(clause) 610 611 # Select by TF families (MATRIX_ANNOTATION.TAG="family") 612 if tf_family: 613 tables.append("MATRIX_ANNOTATION ma2") 614 where_clauses.append("m.ID = ma2.ID") 615 616 clause = "ma2.TAG = 'family'" 617 if isinstance(tf_family, list): 618 # A list of TF families 619 clause = "".join([clause, " and ma2.VAL in ('"]) 620 clause = "".join([clause, "','".join(tf_family)]) 621 clause = "".join([clause, "')"]) 622 else: 623 # A single TF family 624 clause = "".join([clause, " and ma2.VAL = '%s' " % tf_family]) 625 626 where_clauses.append(clause) 627 628 # Select by PAZAR TF ID(s) (MATRIX_ANNOTATION.TAG="pazar_tf_id") 629 if pazar_id: 630 tables.append("MATRIX_ANNOTATION ma3") 631 where_clauses.append("m.ID = ma3.ID") 632 633 clause = "ma3.TAG = 'pazar_tf_id'" 634 if isinstance(pazar_id, list): 635 # A list of PAZAR IDs 636 clause = "".join([clause, " and ma3.VAL in ('"]) 637 clause = "".join([clause, "','".join(pazar_id)]) 638 clause = "".join([clause, "')"]) 639 else: 640 # A single PAZAR ID 641 clause = "".join([" and ma3.VAL = '%s' " % pazar_id]) 642 643 where_clauses.append(clause) 644 645 # Select by PubMed ID(s) (MATRIX_ANNOTATION.TAG="medline") 646 if medline: 647 tables.append("MATRIX_ANNOTATION ma4") 648 where_clauses.append("m.ID = ma4.ID") 649 650 clause = "ma4.TAG = 'medline'" 651 if isinstance(medline, list): 652 # A list of PubMed IDs 653 clause = "".join([clause, " and ma4.VAL in ('"]) 654 clause = "".join([clause, "','".join(medline)]) 655 clause = "".join([clause, "')"]) 656 else: 657 # A single PubMed ID 658 clause = "".join([" and ma4.VAL = '%s' " % medline]) 659 660 where_clauses.append(clause) 661 662 # Select by data type(s) used to compile the matrix 663 # (MATRIX_ANNOTATION.TAG="type") 664 if data_type: 665 tables.append("MATRIX_ANNOTATION ma5") 666 where_clauses.append("m.ID = ma5.ID") 667 668 clause = "ma5.TAG = 'type'" 669 if isinstance(data_type, list): 670 # A list of data types 671 clause = "".join([clause, " and ma5.VAL in ('"]) 672 clause = "".join([clause, "','".join(data_type)]) 673 clause = "".join([clause, "')"]) 674 else: 675 # A single data type 676 clause = "".join([" and ma5.VAL = '%s' " % data_type]) 677 678 where_clauses.append(clause) 679 680 # Select by taxonomic supergroup(s) (MATRIX_ANNOTATION.TAG="tax_group") 681 if tax_group: 682 tables.append("MATRIX_ANNOTATION ma6") 683 where_clauses.append("m.ID = ma6.ID") 684 685 clause = "ma6.TAG = 'tax_group'" 686 if isinstance(tax_group, list): 687 # A list of tax IDs 688 clause = "".join([clause, " and ma6.VAL in ('"]) 689 clause = "".join([clause, "','".join(tax_group)]) 690 clause = "".join([clause, "')"]) 691 else: 692 # A single tax ID 693 clause = "".join([clause, " and ma6.VAL = '%s' " % tax_group]) 694 695 where_clauses.append(clause) 696 697 sql = "".join(["select distinct(m.ID) from ", ", ".join(tables)]) 698 699 if where_clauses: 700 sql = "".join([sql, " where ", " and ".join(where_clauses)]) 701 702 # print "sql = %s" % sql 703 704 cur.execute(sql) 705 rows = cur.fetchall() 706 707 for row in rows: 708 id = row[0] 709 if all_versions: 710 int_ids.append(id) 711 else: 712 # is the latest version? 713 if self._is_latest_version(id): 714 int_ids.append(id) 715 716 if len(int_ids) < 1: 717 warn("Warning: Zero motifs returned with current select critera") 718 719 return int_ids
720
721 - def _is_latest_version(self, int_id):
722 """ 723 Does this internal ID represened the latest version of the JASPAR 724 matrix (collapse on base ids) 725 726 """ 727 cur = self.dbh.cursor() 728 729 cur.execute("select count(*) from MATRIX where BASE_ID = (select BASE_ID from MATRIX where ID = %s) and VERSION > (select VERSION from MATRIX where ID = %s)", (int_id, int_id)) 730 731 row = cur.fetchone() 732 733 count = row[0] 734 735 if count == 0: 736 # no matrices with higher version ID and same base id 737 return True 738 739 return False
740