Call JPL HORIZONS website to obtain ephemerides based on the
        provided targetname, epochs, and observatory_code. For a list
        of valid observatory codes, refer to
        http://minorplanetcenter.net/iau/lists/ObsCodesF.html

        :param observatory_code: str/int;
           observer's location code according to Minor Planet Center
        :param airmass_lessthan: float;
           maximum airmass (optional, default: 99)
        :param solar_elongation: tuple;
           permissible solar elongation range (optional, deg)
        :param skip_daylight: boolean;
           crop daylight epoch during query (optional)
        :result: int; number of epochs queried
        :example: >>> ceres = callhorizons.query('Ceres')
                  >>> ceres.set_epochrange('2016-02-23 00:00', '2016-02-24 00:00', '1h')
                  >>> print (ceres.get_ephemerides(568), 'epochs queried')

        The queried properties and their definitions are:
           +------------------+-----------------------------------------------+
           | Property         | Definition                                    |
           +==================+===============================================+
           | targetname       | official number, name, designation [string]   |
           +------------------+-----------------------------------------------+
           | H                | absolute magnitude in V band (float, mag)     |
           +------------------+-----------------------------------------------+
           | G                | photometric slope parameter (float)           |
           +------------------+-----------------------------------------------+
           | datetime         | epoch date and time (str, YYYY-MM-DD HH:MM:SS)|
           +------------------+-----------------------------------------------+
           | datetime_jd      | epoch Julian Date (float)                     |
           +------------------+-----------------------------------------------+
           | solar_presence   | information on Sun's presence (str)           |
           +------------------+-----------------------------------------------+
           | lunar_presence   | information on Moon's presence (str)          |
           +------------------+-----------------------------------------------+
           | RA               | target RA (float, J2000.0)                    |
           +------------------+-----------------------------------------------+
           | DEC              | target DEC (float, J2000.0)                   |
           +------------------+-----------------------------------------------+
           | RA_rate          | target rate RA (float, arcsec/s)              |
           +------------------+-----------------------------------------------+
           | DEC_rate         | target RA (float, arcsec/s, includes cos(DEC))|
           +------------------+-----------------------------------------------+
           | AZ               | Azimuth meas East(90) of North(0) (float, deg)|
           +------------------+-----------------------------------------------+
           | EL               | Elevation (float, deg)                        |
           +------------------+-----------------------------------------------+
           | airmass          | target optical airmass (float)                |
           +------------------+-----------------------------------------------+
           | magextinct       | V-mag extinction due airmass (float, mag)     |
           +------------------+-----------------------------------------------+
           | V                | V magnitude (comets: total mag) (float, mag)  |
           +------------------+-----------------------------------------------+
           | illumination     | fraction of illuminated disk (float)          |
           +------------------+-----------------------------------------------+
           | EclLon           | heliocentr. ecl. long. (float, deg, J2000.0)  |
           +------------------+-----------------------------------------------+
           | EclLat           | heliocentr. ecl. lat. (float, deg, J2000.0)   |
           +------------------+-----------------------------------------------+
           | ObsEclLon        | obscentr. ecl. long. (float, deg, J2000.0)    |
           +------------------+-----------------------------------------------+
           | ObsEclLat        | obscentr. ecl. lat. (float, deg, J2000.0)     |
           +------------------+-----------------------------------------------+
           | r                | heliocentric distance (float, au)             |
           +------------------+-----------------------------------------------+
           | r_rate           | heliocentric radial rate  (float, km/s)       |
           +------------------+-----------------------------------------------+
           | delta            | distance from the observer (float, au)        |
           +------------------+-----------------------------------------------+
           | delta_rate       | obs-centric radial rate (float, km/s)         |
           +------------------+-----------------------------------------------+
           | lighttime        | one-way light time (float, s)                 |
           +------------------+-----------------------------------------------+
           | elong            | solar elongation (float, deg)                 |
           +------------------+-----------------------------------------------+
           | elongFlag        | app. position relative to Sun (str)           |
           +------------------+-----------------------------------------------+
           | alpha            | solar phase angle (float, deg)                |
           +------------------+-----------------------------------------------+
           | sunTargetPA      | PA of Sun->target vector (float, deg, EoN)    |
           +------------------+-----------------------------------------------+
           | velocityPA       | PA of velocity vector (float, deg, EoN)       |
           +------------------+-----------------------------------------------+
           | GlxLon           | galactic longitude (float, deg)               |
           +------------------+-----------------------------------------------+
           | GlxLat           | galactic latitude  (float, deg)               |
           +------------------+-----------------------------------------------+
           | RA_3sigma        | 3sigma pos. unc. in RA (float, arcsec)        |
           +------------------+-----------------------------------------------+
           | DEC_3sigma       | 3sigma pos. unc. in DEC (float, arcsec)       |
           +------------------+-----------------------------------------------+

def get_ephemerides(self, observatory_code,
                        airmass_lessthan=99,
                        solar_elongation=(0, 180),
                        skip_daylight=False):
        """Call JPL HORIZONS website to obtain ephemerides based on the
        provided targetname, epochs, and observatory_code. For a list
        of valid observatory codes, refer to
        http://minorplanetcenter.net/iau/lists/ObsCodesF.html

        :param observatory_code: str/int;
           observer's location code according to Minor Planet Center
        :param airmass_lessthan: float;
           maximum airmass (optional, default: 99)
        :param solar_elongation: tuple;
           permissible solar elongation range (optional, deg)
        :param skip_daylight: boolean;
           crop daylight epoch during query (optional)
        :result: int; number of epochs queried
        :example: >>> ceres = callhorizons.query('Ceres')
                  >>> ceres.set_epochrange('2016-02-23 00:00', '2016-02-24 00:00', '1h')
                  >>> print (ceres.get_ephemerides(568), 'epochs queried')

        The queried properties and their definitions are:
           +------------------+-----------------------------------------------+
           | Property         | Definition                                    |
           +==================+===============================================+
           | targetname       | official number, name, designation [string]   |
           +------------------+-----------------------------------------------+
           | H                | absolute magnitude in V band (float, mag)     |
           +------------------+-----------------------------------------------+
           | G                | photometric slope parameter (float)           |
           +------------------+-----------------------------------------------+
           | datetime         | epoch date and time (str, YYYY-MM-DD HH:MM:SS)|
           +------------------+-----------------------------------------------+
           | datetime_jd      | epoch Julian Date (float)                     |
           +------------------+-----------------------------------------------+
           | solar_presence   | information on Sun's presence (str)           |
           +------------------+-----------------------------------------------+
           | lunar_presence   | information on Moon's presence (str)          |
           +------------------+-----------------------------------------------+
           | RA               | target RA (float, J2000.0)                    |
           +------------------+-----------------------------------------------+
           | DEC              | target DEC (float, J2000.0)                   |
           +------------------+-----------------------------------------------+
           | RA_rate          | target rate RA (float, arcsec/s)              |
           +------------------+-----------------------------------------------+
           | DEC_rate         | target RA (float, arcsec/s, includes cos(DEC))|
           +------------------+-----------------------------------------------+
           | AZ               | Azimuth meas East(90) of North(0) (float, deg)|
           +------------------+-----------------------------------------------+
           | EL               | Elevation (float, deg)                        |
           +------------------+-----------------------------------------------+
           | airmass          | target optical airmass (float)                |
           +------------------+-----------------------------------------------+
           | magextinct       | V-mag extinction due airmass (float, mag)     |
           +------------------+-----------------------------------------------+
           | V                | V magnitude (comets: total mag) (float, mag)  |
           +------------------+-----------------------------------------------+
           | illumination     | fraction of illuminated disk (float)          |
           +------------------+-----------------------------------------------+
           | EclLon           | heliocentr. ecl. long. (float, deg, J2000.0)  |
           +------------------+-----------------------------------------------+
           | EclLat           | heliocentr. ecl. lat. (float, deg, J2000.0)   |
           +------------------+-----------------------------------------------+
           | ObsEclLon        | obscentr. ecl. long. (float, deg, J2000.0)    |
           +------------------+-----------------------------------------------+
           | ObsEclLat        | obscentr. ecl. lat. (float, deg, J2000.0)     |
           +------------------+-----------------------------------------------+
           | r                | heliocentric distance (float, au)             |
           +------------------+-----------------------------------------------+
           | r_rate           | heliocentric radial rate  (float, km/s)       |
           +------------------+-----------------------------------------------+
           | delta            | distance from the observer (float, au)        |
           +------------------+-----------------------------------------------+
           | delta_rate       | obs-centric radial rate (float, km/s)         |
           +------------------+-----------------------------------------------+
           | lighttime        | one-way light time (float, s)                 |
           +------------------+-----------------------------------------------+
           | elong            | solar elongation (float, deg)                 |
           +------------------+-----------------------------------------------+
           | elongFlag        | app. position relative to Sun (str)           |
           +------------------+-----------------------------------------------+
           | alpha            | solar phase angle (float, deg)                |
           +------------------+-----------------------------------------------+
           | sunTargetPA      | PA of Sun->target vector (float, deg, EoN)    |
           +------------------+-----------------------------------------------+
           | velocityPA       | PA of velocity vector (float, deg, EoN)       |
           +------------------+-----------------------------------------------+
           | GlxLon           | galactic longitude (float, deg)               |
           +------------------+-----------------------------------------------+
           | GlxLat           | galactic latitude  (float, deg)               |
           +------------------+-----------------------------------------------+
           | RA_3sigma        | 3sigma pos. unc. in RA (float, arcsec)        |
           +------------------+-----------------------------------------------+
           | DEC_3sigma       | 3sigma pos. unc. in DEC (float, arcsec)       |
           +------------------+-----------------------------------------------+
        """

        # queried fields (see HORIZONS website for details)
        # if fields are added here, also update the field identification below
        quantities = '1,3,4,8,9,10,18,19,20,21,23,24,27,31,33,36'

        # encode objectname for use in URL
        objectname = urllib.quote(self.targetname.encode("utf8"))

        # construct URL for HORIZONS query
        url = "https://ssd.jpl.nasa.gov/horizons_batch.cgi?batch=l" \
            + "&TABLE_TYPE='OBSERVER'" \
            + "&QUANTITIES='" + str(quantities) + "'" \
              + "&CSV_FORMAT='YES'" \
              + "&ANG_FORMAT='DEG'" \
              + "&CAL_FORMAT='BOTH'" \
              + "&SOLAR_ELONG='" + str(solar_elongation[0]) + "," \
              + str(solar_elongation[1]) + "'" \
              + "&CENTER='"+str(observatory_code)+"'"

        if self.not_smallbody:
            url += "&COMMAND='" + \
                   urllib.quote(self.targetname.encode("utf8")) + "'"
        elif self.cap and self.comet:
            for ident in self.parse_comet():
                if ident is not None:
                    break
            if ident is None:
                ident = self.targetname
            url += "&COMMAND='DES=" + \
                   urllib.quote(ident.encode("utf8")) + "%3B" + \
                   ("CAP'" if self.cap else "'")
        elif self.isorbit_record():
            # Comet orbit record. Do not use DES, CAP. This test must
            # occur before asteroid test.
            url += "&COMMAND='" + \
                   urllib.quote(self.targetname.encode("utf8")) + "%3B'"
        elif self.isasteroid() and not self.comet:
            # for asteroids, use 'DES="designation";'
            for ident in self.parse_asteroid():
                if ident is not None:
                    break
            if ident is None:
                ident = self.targetname
            url += "&COMMAND='" + \
                   urllib.quote(str(ident).encode("utf8")) + "%3B'"
        elif self.iscomet() and not self.asteroid:
            # for comets, potentially append the current apparition
            # (CAP) parameter, or the fragmentation flag (NOFRAG)
            for ident in self.parse_comet():
                if ident is not None:
                    break
            if ident is None:
                ident = self.targetname
            url += "&COMMAND='DES=" + \
                   urllib.quote(ident.encode("utf8")) + "%3B" + \
                   ("NOFRAG%3B" if self.nofrag else "") + \
                   ("CAP'" if self.cap else "'")
        # elif (not self.targetname.replace(' ', '').isalpha() and not
        #      self.targetname.isdigit() and not
        #      self.targetname.islower() and not
        #      self.targetname.isupper()):
        #     # lower case + upper case + numbers = pot. case sensitive designation
        #     url += "&COMMAND='DES=" + \
        #            urllib.quote(self.targetname.encode("utf8")) + "%3B'"
        else:
            url += "&COMMAND='" + \
                   urllib.quote(self.targetname.encode("utf8")) + "%3B'"

        if self.discreteepochs is not None:
            url += "&TLIST="
            for date in self.discreteepochs:
                url += "'" + str(date) + "'"
        elif (self.start_epoch is not None and self.stop_epoch is not None and
              self.step_size is not None):
            url += "&START_TIME='" \
                + urllib.quote(self.start_epoch.encode("utf8")) + "'" \
                + "&STOP_TIME='" \
                + urllib.quote(self.stop_epoch.encode("utf8")) + "'" \
                + "&STEP_SIZE='" + str(self.step_size) + "'"
        else:
            raise IOError('no epoch information given')

        if airmass_lessthan < 99:
            url += "&AIRMASS='" + str(airmass_lessthan) + "'"

        if skip_daylight:
            url += "&SKIP_DAYLT='YES'"
        else:
            url += "&SKIP_DAYLT='NO'"

        self.url = url

        # print (url)

        # call HORIZONS
        i = 0  # count number of connection tries
        while True:
            try:
                src = urllib.urlopen(url).readlines()
                break
            except urllib.URLError:
                time.sleep(0.1)
                # in case the HORIZONS website is blocked (due to another query)
                # wait 0.1 second and try again
            i += 1
            if i > 50:
                return 0  # website could not be reached

        # disseminate website source code
        # identify header line and extract data block (ephemerides data)
        # also extract targetname, absolute mag. (H), and slope parameter (G)
        headerline = []
        datablock = []
        in_datablock = False
        H, G = np.nan, np.nan
        for idx, line in enumerate(src):
            line = line.decode('UTF-8')

            if "Date__(UT)__HR:MN" in line:
                headerline = line.split(',')
            if "$$EOE\n" in line:
                in_datablock = False
            if in_datablock:
                datablock.append(line)
            if "$$SOE\n" in line:
                in_datablock = True
            if "Target body name" in line:
                targetname = line[18:50].strip()
            if ("rotational period in hours)" in
                    src[idx].decode('UTF-8')):
                HGline = src[idx+2].decode('UTF-8').split('=')
                if 'B-V' in HGline[2] and 'G' in HGline[1]:
                    try:
                        H = float(HGline[1].rstrip('G'))
                    except ValueError:
                        pass
                    try:
                        G = float(HGline[2].rstrip('B-V'))
                    except ValueError:
                        pass
            if ("Multiple major-bodies match string" in
                src[idx].decode('UTF-8') or
                ("Matching small-bodies" in src[idx].decode('UTF-8') and not
                    "No matches found" in src[idx+1].decode('UTF-8'))):
                raise ValueError('Ambiguous target name; check URL: %s' %
                                 url)
            if ("Matching small-bodies" in src[idx].decode('UTF-8') and
                    "No matches found" in src[idx+1].decode('UTF-8')):
                raise ValueError('Unknown target; check URL: %s' % url)

        # field identification for each line
        ephemerides = []
        for line in datablock:
            line = line.split(',')

            # ignore line that don't hold any data
            if len(line) < len(quantities.split(',')):
                continue

            this_eph = []
            fieldnames = []
            datatypes = []

            # create a dictionary for each date (each line)
            for idx, item in enumerate(headerline):

                if ('Date__(UT)__HR:MN' in item):
                    this_eph.append(line[idx].strip())
                    fieldnames.append('datetime')
                    datatypes.append(object)
                if ('Date_________JDUT' in item):
                    this_eph.append(np.float64(line[idx]))
                    fieldnames.append('datetime_jd')
                    datatypes.append(np.float64)
                    # read out and convert solar presence
                    try:
                        this_eph.append({'*': 'daylight', 'C': 'civil twilight',
                                         'N': 'nautical twilight',
                                         'A': 'astronomical twilight',
                                         ' ': 'dark',
                                         't': 'transiting'}[line[idx+1]])
                    except KeyError:
                        this_eph.append('n.a.')
                    fieldnames.append('solar_presence')
                    datatypes.append(object)
                    # read out and convert lunar presence
                    try:
                        this_eph.append({'m': 'moonlight',
                                         ' ': 'dark'}[line[idx+2]])
                    except KeyError:
                        this_eph.append('n.a.')
                    fieldnames.append('lunar_presence')
                    datatypes.append(object)
                if (item.find('R.A._(ICRF/J2000.0)') > -1):
                    this_eph.append(np.float64(line[idx]))
                    fieldnames.append('RA')
                    datatypes.append(np.float64)
                if (item.find('DEC_(ICRF/J2000.0)') > -1):
                    this_eph.append(np.float64(line[idx]))
                    fieldnames.append('DEC')
                    datatypes.append(np.float64)
                if (item.find('dRA*cosD') > -1):
                    try:
                        this_eph.append(np.float64(line[idx])/3600.)  # "/s
                    except ValueError:
                        this_eph.append(np.nan)
                    fieldnames.append('RA_rate')
                    datatypes.append(np.float64)
                if (item.find('d(DEC)/dt') > -1):
                    try:
                        this_eph.append(np.float64(line[idx])/3600.)  # "/s
                    except ValueError:
                        this_eph.append(np.nan)
                    fieldnames.append('DEC_rate')
                    datatypes.append(np.float64)
                if (item.find('Azi_(a-app)') > -1):
                    try:  # if AZ not given, e.g. for space telescopes
                        this_eph.append(np.float64(line[idx]))
                        fieldnames.append('AZ')
                        datatypes.append(np.float64)
                    except ValueError:
                        pass
                if (item.find('Elev_(a-app)') > -1):
                    try:  # if EL not given, e.g. for space telescopes
                        this_eph.append(np.float64(line[idx]))
                        fieldnames.append('EL')
                        datatypes.append(np.float64)
                    except ValueError:
                        pass
                if (item.find('a-mass') > -1):
                    try:  # if airmass not given, e.g. for space telescopes
                        this_eph.append(np.float64(line[idx]))
                    except ValueError:
                        this_eph.append(np.nan)
                    fieldnames.append('airmass')
                    datatypes.append(np.float64)
                if (item.find('mag_ex') > -1):
                    try:  # if mag_ex not given, e.g. for space telescopes
                        this_eph.append(np.float64(line[idx]))
                    except ValueError:
                        this_eph.append(np.nan)
                    fieldnames.append('magextinct')
                    datatypes.append(np.float64)
                if (item.find('APmag') > -1):
                    try:
                        this_eph.append(np.float64(line[idx]))
                    except ValueError:
                        this_eph.append(np.nan)
                    fieldnames.append('V')
                    datatypes.append(np.float64)
                if (item.find('Illu%') > -1):
                    try:
                        this_eph.append(np.float64(line[idx]))
                    except ValueError:
                        this_eph.append(np.nan)
                    fieldnames.append('illumination')
                    datatypes.append(np.float64)
                if (item.find('hEcl-Lon') > -1):
                    try:
                        this_eph.append(np.float64(line[idx]))
                    except ValueError:
                        this_eph.append(np.nan)
                    fieldnames.append('EclLon')
                    datatypes.append(np.float64)
                if (item.find('hEcl-Lat') > -1):
                    try:
                        this_eph.append(np.float64(line[idx]))
                    except ValueError:
                        this_eph.append(np.nan)
                    fieldnames.append('EclLat')
                    datatypes.append(np.float64)
                if (item.find('ObsEcLon') > -1):
                    try:
                        this_eph.append(np.float64(line[idx]))
                    except ValueError:
                        this_eph.append(np.nan)
                    fieldnames.append('ObsEclLon')
                    datatypes.append(np.float64)
                if (item.find('ObsEcLat') > -1):
                    try:
                        this_eph.append(np.float64(line[idx]))
                    except ValueError:
                        this_eph.append(np.nan)
                    fieldnames.append('ObsEclLat')
                    datatypes.append(np.float64)
                if (item.find('  r') > -1) and \
                   (headerline[idx+1].find("rdot") > -1):
                    try:
                        this_eph.append(np.float64(line[idx]))
                    except ValueError:
                        this_eph.append(np.nan)
                    fieldnames.append('r')
                    datatypes.append(np.float64)
                if (item.find('rdot') > -1):
                    try:
                        this_eph.append(np.float64(line[idx]))
                    except ValueError:
                        this_eph.append(np.nan)
                    fieldnames.append('r_rate')
                    datatypes.append(np.float64)
                if (item.find('delta') > -1):
                    try:
                        this_eph.append(np.float64(line[idx]))
                    except ValueError:
                        this_eph.append(np.nan)
                    fieldnames.append('delta')
                    datatypes.append(np.float64)
                if (item.find('deldot') > -1):
                    try:
                        this_eph.append(np.float64(line[idx]))
                    except ValueError:
                        this_eph.append(np.nan)
                    fieldnames.append('delta_rate')
                    datatypes.append(np.float64)
                if (item.find('1-way_LT') > -1):
                    try:
                        this_eph.append(np.float64(line[idx])*60.)  # seconds
                    except ValueError:
                        this_eph.append(np.nan)
                    fieldnames.append('lighttime')
                    datatypes.append(np.float64)
                if (item.find('S-O-T') > -1):
                    try:
                        this_eph.append(np.float64(line[idx]))
                    except ValueError:
                        this_eph.append(np.nan)
                    fieldnames.append('elong')
                    datatypes.append(np.float64)
                # in the case of space telescopes, '/r     S-T-O' is used;
                # ground-based telescopes have both parameters in separate
                # columns
                if (item.find('/r    S-T-O') > -1):
                    this_eph.append({'/L': 'leading', '/T': 'trailing'}
                                    [line[idx].split()[0]])
                    fieldnames.append('elongFlag')
                    datatypes.append(object)
                    try:
                        this_eph.append(np.float64(line[idx].split()[1]))
                    except ValueError:
                        this_eph.append(np.nan)
                    fieldnames.append('alpha')
                    datatypes.append(np.float64)
                elif (item.find('S-T-O') > -1):
                    try:
                        this_eph.append(np.float64(line[idx]))
                    except ValueError:
                        this_eph.append(np.nan)
                    fieldnames.append('alpha')
                    datatypes.append(np.float64)
                elif (item.find('/r') > -1):
                    this_eph.append({'/L': 'leading', '/T': 'trailing',
                                     '/?': 'not defined'}
                                    [line[idx]])
                    fieldnames.append('elongFlag')
                    datatypes.append(object)
                if (item.find('PsAng') > -1):
                    try:
                        this_eph.append(np.float64(line[idx]))
                    except ValueError:
                        this_eph.append(np.nan)
                    fieldnames.append('sunTargetPA')
                    datatypes.append(np.float64)
                if (item.find('PsAMV') > -1):
                    try:
                        this_eph.append(np.float64(line[idx]))
                    except ValueError:
                        this_eph.append(np.nan)
                    fieldnames.append('velocityPA')
                    datatypes.append(np.float64)
                if (item.find('GlxLon') > -1):
                    try:
                        this_eph.append(np.float64(line[idx]))
                    except ValueError:
                        this_eph.append(np.nan)
                    fieldnames.append('GlxLon')
                    datatypes.append(np.float64)
                if (item.find('GlxLat') > -1):
                    try:
                        this_eph.append(np.float64(line[idx]))
                    except ValueError:
                        this_eph.append(np.nan)
                    fieldnames.append('GlxLat')
                    datatypes.append(np.float64)
                if (item.find('RA_3sigma') > -1):
                    try:
                        this_eph.append(np.float64(line[idx]))
                    except ValueError:
                        this_eph.append(np.nan)
                    fieldnames.append('RA_3sigma')
                    datatypes.append(np.float64)
                if (item.find('DEC_3sigma') > -1):
                    try:
                        this_eph.append(np.float64(line[idx]))
                    except ValueError:
                        this_eph.append(np.nan)
                    fieldnames.append('DEC_3sigma')
                    datatypes.append(np.float64)
                # in the case of a comet, use total mag for V
                if (item.find('T-mag') > -1):
                    try:
                        this_eph.append(np.float64(line[idx]))
                    except ValueError:
                        this_eph.append(np.nan)
                    fieldnames.append('V')
                    datatypes.append(np.float64)

            # append target name
            this_eph.append(targetname)
            fieldnames.append('targetname')
            datatypes.append(object)

            # append H
            this_eph.append(H)
            fieldnames.append('H')
            datatypes.append(np.float64)

            # append G
            this_eph.append(G)
            fieldnames.append('G')
            datatypes.append(np.float64)

            if len(this_eph) > 0:
                ephemerides.append(tuple(this_eph))

        if len(ephemerides) == 0:
            return 0

        # combine ephemerides with column names and data types into ndarray
        assert len(ephemerides[0]) == len(fieldnames) == len(datatypes)
        self.data = np.array(ephemerides,
                             dtype=[(str(fieldnames[i]), datatypes[i]) for i
                                    in range(len(fieldnames))])

        return len(self)