pywind/elexon/api.py
class B1330(ElexonAPI):
    XML_MAPPING = [
        'timeSeriesID',
        'year',
        'month',
        'congestionAmount',
        'documentType',
        'processType',
        'businessType',
        'resolution',
        'activeFlag',
        'documentID',
        'documentRevNum'
    ]

    def __init__(self, apikey):
        super(B1330, self).__init__(apikey, 'B1330')

    def post_item_cleanup(self, item):
        if 'activeflag' in item:
            item['activeflag'] = item['activeflag'] == 'Y'
        if 'year' in item:
            item['year'] = int(item['year'])

    def rows(self):
        for item in self.items:
            row = item
            row['year'] = str(item['year'])
            row['activeflag'] = str(item['activeflag'])
            yield {'CongestionCosts': row}
pywind/elexon/api.py
class B1630(ElexonAPI):
    XML_MAPPING = [
        'documentType',
        'businessType',
        'processType',
        'timeSeriesID',
        'quantity',
        'curveType',
        'resolution',
        'settlementDate',
        'settlementPeriod',
        'PSRType',
        'powerSystemResourceType',
        'registeredResourceEICCode',
        'marketGenerationUnitEICCode',
        'activeFlag',
        'documentID',
        'documentRevNum'
    ]

    def __init__(self, apikey):
        super(B1630, self).__init__(apikey, 'B1630')

    def rows(self):
        for item in self.items:
            row = item.copy()
            row['activeflag'] = str(item['activeflag'])
            yield {'ConfigurationData': row}
pywind/elexon/api.py
class FUELINST(ElexonAPI):
    """ Instant Generation by Fuel Type """
    XML_MAPPING = [
        'recordType',
        'startTimeOfHalfHrPeriod',
        'settlementPeriod',
        'publishingPeriodCommencingTime',
        'ccgt',
        'oil',
        'coal',
        'nuclear',
        'wind',
        'ps',
        'npshyd',
        'ocgt',
        'other',
        'intfr',
        'intirl',
        'intned',
        'intew',
        'activeFlag'
    ]

    def __init__(self, apikey=None):
        super(FUELINST, self).__init__(apikey, 'FUELINST')

    def post_item_cleanup(self, item):
        dttm = datetime.strptime(item['publishingperiodcommencingtime'], "%Y-%m-%d %H:%M:%S")
        item['date'] = dttm.date()
        item['time'] = dttm.time()
pywind/utils.py
class StdoutFormatter(object):
    """
    Small class to provide easier printing to stdout.

    .. code::

       >>> from pywind.utils import StdoutFormatter
       >>> sof = StdoutFormatter("5s", "6s", ">10s")
       >>> sof.titles("Hello", "World", "right")
         Hello  World        right
         -----  ------  ----------
       >>> sof.row("first", "row", "right")
         first  row          right

    .. note::

      The format detection doesn't allow all options :-( "10,d" is not yet supported.

    """
    def __init__(self, *args, **kwargs):
        self.columns = []
        for arg in args:
            ssz = arg[:-1] if arg[0].isdigit() else arg[1:-1]
            fmt = [arg[0] if not arg[0].isdigit() else '',
                   int(ssz) if arg[-1] != 'f' else float(ssz),
                   arg[-1],
                   int(ssz) if arg[-1] != 'f' else int(ssz.split('.')[0])]
            self.columns.append(fmt)
        self.spaces = kwargs.get('spaces', "  ")

    def formatter(self, titles=False):
        """ Return the format string for the columns configured.

        :param titles: True if the format will be used for titles (all strings)
        :returns: Format string
        :rtype: str
        """
        fmts = []
        for col in self.columns:
            ssz = col[1] if titles is False else col[3]
            fmts.append("{{:{}{}{}}}".format(col[0], ssz, col[2] if titles is False else 's'))
        return self.spaces + self.spaces.join(fmts)

    def titles(self, *args):
        """ Generate the title string block.

        :param args: List of titles to use. Should be at least as long as the number of columns
        :returns: Formatted title string
        :rtype: str
        """
        if len(args) < len(self.columns):
            raise AttributeError("Incorrect number of titles supplied. Should have {}, got {}".
                                 format(len(self.columns), len(args)))
        fmt = self.formatter(True)
        return fmt.format(*args) + "\n" + \
               fmt.format(*['-' * col[3] for col in self.columns])

    def row(self, *args):
        """ Use the column format to generate a string. This tries to truncate long strings.

        :param args: The column values.
        :returns: Formatted string using args
        :rtype: str
        """
        vals = []
        col = 0
        for arg in args:
            if self.columns[col][2] == 's' and len(arg) > self.columns[col][3]:
                vals.append(arg[:self.columns[col][3] - 3] + '...')
            else:
                vals.append(arg)
            col += 1
        return self.formatter().format(*vals)
pywind/elexon/api.py
class B1610(ElexonAPI):
    def __init__(self, apikey):
        super(B1610, self).__init__(apikey, 'B1610')

    def post_item_cleanup(self, item):
        item['quantity'] = float(item['quantity'])

    def rows(self):
        for item in self.items:
            row = item.copy()
            row['activeflag'] = str(item['activeflag'])
            yield {'ConfigurationData': row}
pywind/elexon/api.py
class DERBMDATA(ElexonAPI):
    """ Derived Balancing Mechanism Data """
    MULTI_RESULTS = (
        ('bav', '/response/responseBody/bav/responseList/item'),
        ('oav', '/response/responseBody/oav/responseList/item'),
        ('ipbav', '/response/responseBody/ipbav/responseList/item'),
        ('ipoav', '/response/responseBody/ipoav/responseList/item'),
        ('ipbc', '/response/responseBody/ipbc/responseList/item'),
        ('ipoc', '/response/responseBody/ipoc/responseList/item'),
    )

    def __init__(self, apikey=None):
        super(DERBMDATA, self).__init__(apikey, 'DERBMDATA')

    def post_item_cleanup(self, item):
        item['settlementperiod'] = int(item['settlementperiod'])
        for key in item:
            if 'volume' in key or 'cashflow' in key or 'total' in key:
                item[key] = float(item[key])
pywind/elexon/api.py
class UOU2T52W(ElexonAPI):
    """ National Output Useable by Fuel Type and BM Unit (2-52 Weeks Ahead)"""
    def __init__(self, apikey=None):
        super(UOU2T52W, self).__init__(apikey, 'UOU2T52W')
pywind/utils.py
def args_get_datetime(args):
    if args.fromdate and args.fromtime:
        args.fromdatetime = datetime.combine(args.fromdate, args.fromtime)
    else:
        args.fromdatetime = None
    if args.todate and args.totime:
        args.todatetime = datetime.combine(args.todate, args.totime)
    else:
        args.todatetime = None
pywind/elexon/api.py
class B1420(ElexonAPI):
    XML_MAPPING = [
        'documentType',
        'businessType',
        'processType',
        'timeSeriesID',
        'powerSystemResourceType',
        'year',
        'bMUnitID',
        'registeredResourceEICCode',
        'nominal',
        'nGCBMUnitID',
        'registeredResourceName',
        'activeFlag',
        'documentID',
        'implementationDate',
        'powerSystemResourceType'
    ]

    def __init__(self, apikey):
        super(B1420, self).__init__(apikey, 'B1420')

    def post_item_cleanup(self, item):
        if 'nominal' in item:
            item['nominal'] = float(item['nominal'])
        if 'powersystemresourcetype' in item:
            item['powersystemresourcetype'] = item['powersystemresourcetype'].replace('\"', '')
#        if 'activeflag' in item:
#            item['activeflag'] = item['activeflag'] == 'Y'

    def rows(self):
        for item in self.items:
            row = item.copy()
            row['year'] = str(item['year'])
            row['nominal'] = "{:10.1f}".format(item['nominal']).strip()
            row['activeflag'] = str(item['activeflag'])
            yield {'ConfigurationData': row}
pywind/elexon/api.py
class DERSYSDATA(ElexonAPI):
    """ Derived System Data """
    def __init__(self, apikey=None):
        super(DERSYSDATA, self).__init__(apikey, 'DERSYSDATA')

    def post_item_cleanup(self, item):
        item['settlementdate'] = datetime.strptime(item['settlementdate'], "%Y-%m-%d").date()
        item['activeflag'] = item['activeflag'] == 'Y'

        for key in item.keys():
            if key in ['recordtype', 'settlementdate', 'settlementperiod', 'pricederivationcode',
                       'bsaddefault', 'activeflag'] or item[key] == 'NULL':
                continue
            item[key] = float(item[key])
pywind/elexon/api.py
class BMUNITSEARCH(ElexonAPI):
    """ Balancing Mechanism Unit Search """
    XML_MAPPING = [
        'recordType',
        'bmUnitID',
        'bmUnitType',
        'leadPartyName',
        'ngcBMUnitName',
        'activeFlag',
    ]

    CATEGORIES = {
        '2': 'Supplier',
        'C': 'Additional Supplier',
        'E': 'Embedded',
        'G': 'Unknown',
        'I': 'Interconnector',
        'M': 'Miscellaneous',
        'S': 'Unknown',
        'T': 'Directly connected'
    }

    def __init__(self, apikey=None):
        super(BMUNITSEARCH, self).__init__(apikey, 'BMUNITSEARCH')

    def post_item_cleanup(self, item):
        item['category'] = self.CATEGORIES[item['bmunittype']]
pywind/elexon/api.py
class B1320(ElexonAPI):
    XML_MAPPING = [
        'timeSeriesID',
        'settlementDate',
        'settlementPeriod',
        'quantity',
        'flowDirection',
        'reasonCode',
        'documentType',
        'processType',
        'resolution',
        'curveType',
        'activeFlag',
        'documentID',
        'documentRevNum'
    ]

    def __init__(self, apikey):
        super(B1320, self).__init__(apikey, 'B1320')

    def post_item_cleanup(self, item):
        if 'activeflag' in item:
            item['activeflag'] = item['activeflag'] == 'Y'
        if 'quantity' in item:
            item['quantity'] = float(item['quantity'])

    def rows(self):
        for item in self.items:
            row = item.copy()
            row['quantity'] = "{:10.4f}".format(item['quantity']).strip()
            row['activeflag'] = str(item['activeflag'])
            yield {'CongestionCounterTrade': row}
pywind/elexon/unit.py
class BalancingData(object):
    """ Parent class to hold data from the :mod:DERBMDATA API. """
    def __init__(self, api_key):
        self.api = DERBMDATA(api_key)
        self.units = {}

    def get_data(self, **params):
        if self.api.get_data(**params) is False:
            return False

        for element in self.api.multi:
            for item in self.api.multi[element]:
                if item['total'] == 0:
                    continue
                unit = self.units.setdefault(item['ngcbmunitname'],
                                             BalancingUnitData(item))
                unit.add_data(element, item)
        return True


Question: from datetime import timedelta, time, datetime, date
from pywind.elexon.api import B1420, B1330, B1320, FUELINST, \
                              DERSYSDATA, DERBMDATA, BMUNITSEARCH, \
                              B1610, B1630, UOU2T52W
from pywind.elexon.unit import BalancingData
from pywind.utils import StdoutFormatter, args_get_datetime
def elexon_b1420(args):
    """ Installed Generation Capacity per Unit """
    if not check_api_key(args):
        return None

    api = B1420(args.apikey)
    if not api.get_data(**{'Year': args.year or 2016}):
        print("No data returned.")
        return None

    fmt = StdoutFormatter("30s", "8s", "10s", "6s", "10.1f", "20s")
    print("\n" + fmt.titles('Resource Name', 'NGC Id', 'BM Unit Id', 'Active', 'Output', 'Type'))
    for item in sorted(api.items, key=lambda xxx: xxx['ngcbmunitid']):
        print(fmt.row(item['registeredresourcename'],
                      item['ngcbmunitid'],
                      item['bmunitid'],
                      str(item['activeflag']),
                      float(item['nominal']),
                      item.get('powersystemresourcetype', 'n/a')))

    return api


def elexon_b1610(args):
    """ Generated output by generator """
    if not check_api_key(args):
        return None

    api = B1610(args.apikey)
    if args.settlement_period is None:
        print("A settlement period should be supplied using the --settlement-period flag (range 1 to 50)."
              "Defaulting to 1")
    if args.date is None:
        print("A date should be supplied using the --date flag. Format is YYYY-MM-DD. Defaulting to today")
    if not api.get_data(**{'SettlementDate': args.date or date.today().strftime("%Y-%m-%d"),
                           'Period': args.settlement_period or 1}):
        print("No data returned.")
        return None

    fmt = StdoutFormatter("8s", "10s", "6s", "6s", "10.1f", "20s", "30s")
    print("\n" + fmt.titles('NGC Unit', 'Date', 'Period', 'Active', 'Output', 'Type', 'Reference'))
    for item in sorted(api.items, key=lambda xxx: xxx['ngcbmunitid']):
        print(fmt.row(item['ngcbmunitid'],
                      item['settlementdate'],
                      str(item['settlementperiod']),
                      str(item['activeflag']),
                      float(item['quantity']),
                      item.get('powersystemresourcetype', 'n/a'),
                      item['documentid'] + " - " + item['documentrevnum']))

    return api


def elexon_b1630(args):
    """ Actual or forecast Wind & Solar Generation """
    if not check_api_key(args):
        return None

    api = B1630(args.apikey)
    if args.settlement_period is None:
        print("A settlement period should be supplied using the --settlement-period flag (range 1 to 50)."
              "Defaulting to 1")
    if args.date is None:
        print("A date should be supplied using the --date flag. Format is YYYY-MM-DD. Defaulting to today")
    if not api.get_data(**{'SettlementDate': args.date or date.today().strftime("%Y-%m-%d"),
                           'Period': args.settlement_period or 1}):
        print("No data returned.")
        return None

    fmt = StdoutFormatter("10s", "6s", "6s", "10.1f", "20s", "30s")
    print("\n" + fmt.titles('Date', 'Period', 'Active', 'Output', 'Type', 'Reference'))
    for item in sorted(api.items, key=lambda xxx: xxx['documentid']):
        print(fmt.row(item['settlementdate'],
                      str(item['settlementperiod']),
                      str(item['activeflag']),
                      float(item['quantity']),
                      item.get('powersystemresourcetype', 'n/a'),
                      item['documentid'] + " - " + item['documentrevnum']))

    return api


def elexon_sbp(args):
    """ Derived System Prices from Elexon """
    if not check_api_key(args):
        return None

    api = DERSYSDATA(args.apikey)

    params = {
        'FromSettlementDate': args.fromdate or date.today() - timedelta(days=1),
        'ToSettlementDate': args.todate or args.fromdate or (date.today()) - timedelta(days=1)
    }
    if args.period is not None:
        params['SettlementPeriod'] = args.period
    if args.all_periods:
        params['SettlementPeriod'] = '*'

    if get_check_data(api, params) is False:
        return None

    fmt = StdoutFormatter("15s", "^20d", "15.4f", "15.4f", "4s")
    print("\nSystem adjustments are included in the figures shown below where '*' is shown.\n")
    print("\n" + fmt.titles('Date', 'Settlement Period', 'Sell Price', 'Buy Price', 'Adj?'))
    for item in api.items:
        print(fmt.row(item['settlementdate'].strftime("%Y %b %d"),
                      item['settlementperiod'],
                      item['systemsellprice'] + item['sellpriceadjustment'],
                      item['systembuyprice'] + item['buypriceadjustment'],
                      "*" if item['sellpriceadjustment'] + item['buypriceadjustment'] > 0 else ''
                      ))

    return api


def elexon_bm_data(args):
    """ Derived System Prices from Elexon """
    if not check_api_key(args):
        return None


Answer:     bd = BalancingData(args.apikey)