| 381 | |
| 382 | |
| 383 | def has_header(self, sample): |
| 384 | # Creates a dictionary of types of data in each column. If any |
| 385 | # column is of a single type (say, integers), *except* for the first |
| 386 | # row, then the first row is presumed to be labels. If the type |
| 387 | # can't be determined, it is assumed to be a string in which case |
| 388 | # the length of the string is the determining factor: if all of the |
| 389 | # rows except for the first are the same length, it's a header. |
| 390 | # Finally, a 'vote' is taken at the end for each column, adding or |
| 391 | # subtracting from the likelihood of the first row being a header. |
| 392 | |
| 393 | rdr = reader(StringIO(sample), self.sniff(sample)) |
| 394 | |
| 395 | header = next(rdr) # assume first row is header |
| 396 | |
| 397 | columns = len(header) |
| 398 | columnTypes = {} |
| 399 | for i in range(columns): columnTypes[i] = None |
| 400 | |
| 401 | checked = 0 |
| 402 | for row in rdr: |
| 403 | # arbitrary number of rows to check, to keep it sane |
| 404 | if checked > 20: |
| 405 | break |
| 406 | checked += 1 |
| 407 | |
| 408 | if len(row) != columns: |
| 409 | continue # skip rows that have irregular number of columns |
| 410 | |
| 411 | for col in list(columnTypes.keys()): |
| 412 | thisType = complex |
| 413 | try: |
| 414 | thisType(row[col]) |
| 415 | except (ValueError, OverflowError): |
| 416 | # fallback to length of string |
| 417 | thisType = len(row[col]) |
| 418 | |
| 419 | if thisType != columnTypes[col]: |
| 420 | if columnTypes[col] is None: # add new column type |
| 421 | columnTypes[col] = thisType |
| 422 | else: |
| 423 | # type is inconsistent, remove column from |
| 424 | # consideration |
| 425 | del columnTypes[col] |
| 426 | |
| 427 | # finally, compare results against first row and "vote" |
| 428 | # on whether it's a header |
| 429 | hasHeader = 0 |
| 430 | for col, colType in columnTypes.items(): |
| 431 | if type(colType) == type(0): # it's a length |
| 432 | if len(header[col]) != colType: |
| 433 | hasHeader += 1 |
| 434 | else: |
| 435 | hasHeader -= 1 |
| 436 | else: # attempt typecast |
| 437 | try: |
| 438 | colType(header[col]) |
| 439 | except (ValueError, TypeError): |
| 440 | hasHeader += 1 |