Exemplo n.º 1
0
    def wfs_request_compare(self, request):
        project = self.testdata_path + "test_project_wfs.qgs"
        assert os.path.exists(project), "Project file not found: " + project

        query_string = 'MAP=%s&SERVICE=WFS&VERSION=1.0.0&REQUEST=%s' % (urllib.parse.quote(project), request)
        header, body = self.server.handleRequest(query_string)
        self.assert_headers(header, body)
        response = header + body
        f = open(self.testdata_path + 'wfs_' + request.lower() + '.txt', 'rb')
        expected = f.read()
        f.close()
        # Store the output for debug or to regenerate the reference documents:
        """
        f = open(os.path.dirname(__file__) + '/wfs_' +  request.lower() + '_expected.txt', 'w+')
        f.write(expected)
        f.close()
        f = open(os.path.dirname(__file__) + '/wfs_' +  request.lower() + '_response.txt', 'w+')
        f.write(response)
        f.close()
        """
        response = re.sub(RE_STRIP_UNCHECKABLE, b'', response)
        expected = re.sub(RE_STRIP_UNCHECKABLE, b'', expected)

        # for older GDAL versions (<2.0), id field will be integer type
        if int(osgeo.gdal.VersionInfo()[:1]) < 2:
            expected = expected.replace(b'<element type="long" name="id"/>', b'<element type="integer" name="id"/>')

        self.assertXMLEqual(response, expected, msg="request %s failed.\n Query: %s\n Expected:\n%s\n\n Response:\n%s" % (query_string, request, expected.decode('utf-8'), response.decode('utf-8')))
Exemplo n.º 2
0
    def wms_request_compare(self, request, extra=None, reference_file=None):
        project = self.testdata_path + "test_project.qgs"
        assert os.path.exists(project), "Project file not found: " + project

        query_string = 'MAP=%s&SERVICE=WMS&VERSION=1.3&REQUEST=%s' % (urllib.parse.quote(project), request)
        if extra is not None:
            query_string += extra
        header, body = self.server.handleRequest(query_string)
        response = header + body
        reference_path = self.testdata_path + (request.lower() if not reference_file else reference_file) + '.txt'
        f = open(reference_path, 'rb')
        expected = f.read()
        f.close()
        # Store the output for debug or to regenerate the reference documents:
        """
        f = open(reference_path, 'wb+')
        f.write(response)
        f.close()

        f = open(os.path.dirname(__file__) + '/expected.txt', 'w+')
        f.write(expected)
        f.close()
        f = open(os.path.dirname(__file__) + '/response.txt', 'w+')
        f.write(response)
        f.close()
        #"""
        response = re.sub(RE_STRIP_UNCHECKABLE, b'*****', response)
        expected = re.sub(RE_STRIP_UNCHECKABLE, b'*****', expected)

        # for older GDAL versions (<2.0), id field will be integer type
        if int(osgeo.gdal.VersionInfo()[:1]) < 2:
            expected = expected.replace(b'typeName="Integer64" precision="0" length="10" editType="TextEdit" type="qlonglong"', b'typeName="Integer" precision="0" length="10" editType="TextEdit" type="int"')

        self.assertXMLEqual(response, expected, msg="request %s failed.\n Query: %s\n Expected:\n%s\n\n Response:\n%s" % (query_string, request, expected.decode('utf-8'), response.decode('utf-8')))
Exemplo n.º 3
0
    def wmts_request_compare_project(self, project, request, version='', extra_query_string='', reference_base_name=None):
        query_string = 'https://www.qgis.org/?SERVICE=WMTS&REQUEST=%s' % (request)
        if version:
            query_string += '&VERSION=%s' % version

        if extra_query_string:
            query_string += '&%s' % extra_query_string

        header, body = self._execute_request_project(query_string, project)
        self.assert_headers(header, body)
        response = header + body

        if reference_base_name is not None:
            reference_name = reference_base_name
        else:
            reference_name = 'wmts_' + request.lower()

        reference_name += '.txt'
        reference_path = self.testdata_path + reference_name

        self.store_reference(reference_path, response)
        f = open(reference_path, 'rb')
        expected = f.read()
        f.close()
        response = re.sub(RE_STRIP_UNCHECKABLE, b'', response)
        expected = re.sub(RE_STRIP_UNCHECKABLE, b'', expected)

        self.assertXMLEqual(response, expected, msg="request %s failed.\n Query: %s" % (query_string, request))
Exemplo n.º 4
0
    def wms_inspire_request_compare(self, request):
        """WMS INSPIRE tests"""
        project = self.testdata_path + "test_project_inspire.qgs"
        assert os.path.exists(project), "Project file not found: " + project

        query_string = "MAP=%s&SERVICE=WMS&VERSION=1.3.0&REQUEST=%s" % (urllib.parse.quote(project), request)
        header, body = self.server.handleRequest(query_string)
        response = header + body
        f = open(self.testdata_path + request.lower() + "_inspire.txt", "rb")
        expected = f.read()
        f.close()
        # Store the output for debug or to regenerate the reference documents:
        """
        f = open(os.path.dirname(__file__) + '/expected.txt', 'w+')
        f.write(expected)
        f.close()
        f = open(os.path.dirname(__file__) + '/response.txt', 'w+')
        f.write(response)
        f.close()
        """
        response = re.sub(RE_STRIP_UNCHECKABLE, b"", response)
        expected = re.sub(RE_STRIP_UNCHECKABLE, b"", expected)
        self.assertXMLEqual(
            response,
            expected,
            msg="request %s failed.\n Query: %s\n Expected:\n%s\n\n Response:\n%s"
            % (query_string, request, expected.decode("utf-8"), response.decode("utf-8")),
        )
Exemplo n.º 5
0
    def wms_request_compare(self, request, extra=None, reference_file=None, project='test_project.qgs', version='1.3.0', ignoreExtent=False, normalizeJson=False):
        response_header, response_body, query_string = self.wms_request(request, extra, project, version)
        response = response_header + response_body
        reference_path = self.testdata_path + (request.lower() if not reference_file else reference_file) + '.txt'
        self.store_reference(reference_path, response)
        f = open(reference_path, 'rb')
        expected = f.read()

        def _n(r):
            lines = r.split(b'\n')
            b = lines[2:]
            h = lines[:2]
            try:
                return b'\n'.join(h) + json.dumps(json.loads(b'\n'.join(b))).encode('utf8')
            except:
                return r

        response = _n(response)
        expected = _n(expected)

        f.close()
        response = re.sub(RE_STRIP_UNCHECKABLE, b'*****', response)
        expected = re.sub(RE_STRIP_UNCHECKABLE, b'*****', expected)
        if ignoreExtent:
            response = re.sub(RE_STRIP_EXTENTS, b'*****', response)
            expected = re.sub(RE_STRIP_EXTENTS, b'*****', expected)

        msg = "request %s failed.\nQuery: %s\nExpected file: %s\nResponse:\n%s" % (query_string, request, reference_path, response.decode('utf-8'))
        self.assertXMLEqual(response, expected, msg=msg)
Exemplo n.º 6
0
    def wms_request_compare(self, request, extra=None, reference_file=None):
        project = self.testdata_path + "test_project.qgs"
        assert os.path.exists(project), "Project file not found: " + project

        query_string = 'MAP=%s&SERVICE=WMS&VERSION=1.3&REQUEST=%s' % (urllib.parse.quote(project), request)
        if extra is not None:
            query_string += extra
        header, body = self.server.handleRequest(query_string)
        response = header + body
        reference_path = self.testdata_path + (request.lower() if not reference_file else reference_file) + '.txt'
        f = open(reference_path, 'rb')
        expected = f.read()
        f.close()
        # Store the output for debug or to regenerate the reference documents:
        """
        f = open(reference_path, 'wb+')
        f.write(response)
        f.close()

        f = open(os.path.dirname(__file__) + '/expected.txt', 'w+')
        f.write(expected)
        f.close()
        f = open(os.path.dirname(__file__) + '/response.txt', 'w+')
        f.write(response)
        f.close()
        #"""
        response = re.sub(RE_STRIP_UNCHECKABLE, b'*****', response)
        expected = re.sub(RE_STRIP_UNCHECKABLE, b'*****', expected)

        self.assertXMLEqual(response, expected, msg="request %s failed.\n Query: %s\n Expected:\n%s\n\n Response:\n%s" % (query_string, request, expected.decode('utf-8'), response.decode('utf-8')))
Exemplo n.º 7
0
    def wfs_request_compare(self, request, version='', extra_query_string='', reference_base_name=None):
        project = self.testdata_path + "test_project_wfs.qgs"
        assert os.path.exists(project), "Project file not found: " + project

        query_string = '?MAP=%s&SERVICE=WFS&REQUEST=%s' % (urllib.parse.quote(project), request)
        if version:
            query_string += '&VERSION=%s' % version

        if extra_query_string:
            query_string += '&%s' % extra_query_string

        header, body = self._execute_request(query_string)
        self.assert_headers(header, body)
        response = header + body

        if reference_base_name is not None:
            reference_name = reference_base_name
        else:
            reference_name = 'wfs_' + request.lower()

        if version == '1.0.0':
            reference_name += '_1_0_0'
        reference_name += '.txt'

        reference_path = self.testdata_path + reference_name

        self.store_reference(reference_path, response)
        f = open(reference_path, 'rb')
        expected = f.read()
        f.close()
        response = re.sub(RE_STRIP_UNCHECKABLE, b'', response)
        expected = re.sub(RE_STRIP_UNCHECKABLE, b'', expected)

        self.assertXMLEqual(response, expected, msg="request %s failed.\n Query: %s" % (query_string, request))
Exemplo n.º 8
0
    def wms_request_compare(self, request, extra=None, reference_file=None, project='test_project.qgs', version='1.3.0'):
        response_header, response_body, query_string = self.wms_request(request, extra, project, version)
        response = response_header + response_body
        reference_path = self.testdata_path + (request.lower() if not reference_file else reference_file) + '.txt'
        self.store_reference(reference_path, response)
        f = open(reference_path, 'rb')
        expected = f.read()
        f.close()
        response = re.sub(RE_STRIP_UNCHECKABLE, b'*****', response)
        expected = re.sub(RE_STRIP_UNCHECKABLE, b'*****', expected)

        msg = "request %s failed.\nQuery: %s\nExpected file: %s\nResponse:\n%s" % (query_string, request, reference_path, response.decode('utf-8'))
        self.assertXMLEqual(response, expected, msg=msg)
Exemplo n.º 9
0
    def wms_inspire_request_compare(self, request):
        """WMS INSPIRE tests"""
        project = self.testdata_path + "test_project_inspire.qgs"
        assert os.path.exists(project), "Project file not found: " + project

        query_string = '?MAP=%s&SERVICE=WMS&VERSION=1.3.0&REQUEST=%s' % (urllib.parse.quote(project), request)
        header, body = self._execute_request(query_string)
        response = header + body
        reference_path = self.testdata_path + request.lower() + '_inspire.txt'
        self.store_reference(reference_path, response)
        f = open(reference_path, 'rb')
        expected = f.read()
        f.close()
        response = re.sub(RE_STRIP_UNCHECKABLE, b'', response)
        expected = re.sub(RE_STRIP_UNCHECKABLE, b'', expected)
        self.assertXMLEqual(response, expected, msg="request %s failed.\nQuery: %s\nExpected file: %s\nResponse:\n%s" % (query_string, request, reference_path, response.decode('utf-8')))
Exemplo n.º 10
0
    def wcs_request_compare(self, request):
        project = self.projectPath
        assert os.path.exists(project), "Project file not found: " + project

        query_string = '?MAP=%s&SERVICE=WCS&VERSION=1.0.0&REQUEST=%s' % (urllib.parse.quote(project), request)
        header, body = self._execute_request(query_string)
        self.assert_headers(header, body)
        response = header + body
        reference_path = self.testdata_path + 'wcs_' + request.lower() + '.txt'
        f = open(reference_path, 'rb')
        self.store_reference(reference_path, response)
        expected = f.read()
        f.close()
        response = re.sub(RE_STRIP_UNCHECKABLE, b'', response)
        expected = re.sub(RE_STRIP_UNCHECKABLE, b'', expected)

        self.assertXMLEqual(response, expected, msg="request %s failed.\n Query: %s\n Expected:\n%s\n\n Response:\n%s" % (query_string, request, expected.decode('utf-8'), response.decode('utf-8')))
Exemplo n.º 11
0
    def wms_request_compare(self, request, extra=None, reference_file=None, project='test_project.qgs'):
        project = self.testdata_path + project
        assert os.path.exists(project), "Project file not found: " + project

        query_string = 'https://www.qgis.org/?MAP=%s&SERVICE=WMS&VERSION=1.3&REQUEST=%s' % (urllib.parse.quote(project), request)
        if extra is not None:
            query_string += extra
        header, body = self._execute_request(query_string)
        response = header + body
        reference_path = self.testdata_path + (request.lower() if not reference_file else reference_file) + '.txt'
        self.store_reference(reference_path, response)
        f = open(reference_path, 'rb')
        expected = f.read()
        f.close()
        response = re.sub(RE_STRIP_UNCHECKABLE, b'*****', response)
        expected = re.sub(RE_STRIP_UNCHECKABLE, b'*****', expected)

        self.assertXMLEqual(response, expected, msg="request %s failed.\nQuery: %s\nExpected file: %s\nResponse:\n%s" % (query_string, request, reference_path, response.decode('utf-8')))
Exemplo n.º 12
0
    def wcs_request_compare(self, request):
        project = self.projectPath
        assert os.path.exists(project), "Project file not found: " + project

        query_string = '?MAP=%s&SERVICE=WCS&VERSION=1.0.0&REQUEST=%s' % (
            urllib.parse.quote(project), request)
        header, body = self._execute_request(query_string)
        self.assert_headers(header, body)
        response = header + body
        reference_path = self.testdata_path + 'wcs_' + request.lower() + '.txt'
        f = open(reference_path, 'rb')
        self.store_reference(reference_path, response)
        expected = f.read()
        f.close()
        response = re.sub(RE_STRIP_UNCHECKABLE, b'', response)
        expected = re.sub(RE_STRIP_UNCHECKABLE, b'', expected)

        self.assertXMLEqual(
            response,
            expected,
            msg=
            "request %s failed.\n Query: %s\n Expected:\n%s\n\n Response:\n%s"
            % (query_string, request, expected.decode('utf-8'),
               response.decode('utf-8')))
Exemplo n.º 13
0
    def wfs_request_compare(self, request):
        project = self.testdata_path + "test_project_wfs.qgs"
        assert os.path.exists(project), "Project file not found: " + project

        query_string = 'MAP=%s&SERVICE=WFS&VERSION=1.0.0&REQUEST=%s' % (urllib.parse.quote(project), request)
        header, body = self.server.handleRequest(query_string)
        self.assert_headers(header, body)
        response = header + body
        f = open(self.testdata_path + 'wfs_' + request.lower() + '.txt', 'rb')
        expected = f.read()
        f.close()
        # Store the output for debug or to regenerate the reference documents:
        """
        f = open(os.path.dirname(__file__) + '/wfs_' +  request.lower() + '_expected.txt', 'w+')
        f.write(expected)
        f.close()
        f = open(os.path.dirname(__file__) + '/wfs_' +  request.lower() + '_response.txt', 'w+')
        f.write(response)
        f.close()
        """
        response = re.sub(RE_STRIP_UNCHECKABLE, b'', response)
        expected = re.sub(RE_STRIP_UNCHECKABLE, b'', expected)

        self.assertXMLEqual(response, expected, msg="request %s failed.\n Query: %s\n Expected:\n%s\n\n Response:\n%s" % (query_string, request, expected.decode('utf-8'), response.decode('utf-8')))
Exemplo n.º 14
0
async def prestige(*,request : str):
    """Returns data on prestige results for the two crew members entered as input"""
    if request.lower()=="visiri capt'n": #Visiri Captain is weird, okay?
        result=(set([x for x in unique if x[0]=="Visiri Capt'n"][0][1:]))
        await bot.say("%s is recorded as being used in ```%s```"%("Visiri Capt'n", result))
        return
    if ',' in request:
        names = request.lower().split(',')
    else: #If there's only one name, this tree will handle it. It will try to give all receipes for the one crew member
        if request.lower() in heroes:
            result=(set([x for x in hero if x[0]==request.title()][0][1:]))            
        elif request.lower() in epics:
            if request.lower()=='trumpsta':
                request='King Trumpsta'
            result=(set([x for x in epic if x[0]==request.title()][0][1:]))            
        elif request.lower() in uniques:
            result=(set([x for x in unique if x[0]==request.title()][0][1:]))            
        else:
            await bot.say("Unrecognized or the crew is not hero, epic, or unique. Please check spelling with ?namelist")
            return
        if result==set():
            await bot.say("No known recipes including %s"%(request.title()))
            return
        else:
            await bot.say("%s is recorded as being used in ```%s```"%(request.title(), result))
            return
    if names[1][0] == ' ':
        names[1] = names[1][1:]
    try: #Returns plain prestige results
        if prestiges[r"%s_%s"%(names[0],names[1])]=='':
            if prestiges[r"%s_%s"%(names[1],names[0])]=='':
                await bot.say("I don't appear to have any results for this combination.")
                return
            else:
                await bot.say("%s + %s = %s"%(names[0].title(),names[1].title(),prestiges[r"%s_%s"%(names[1],names[0])]))
                return
        else:
            await bot.say("%s + %s = %s"%(names[0].title(),names[1].title(),prestiges[r"%s_%s"%(names[1],names[0])]))
            return
    except:
        await bot.say("Please separate names by a comma (,) and reference ?namelist for spelling. Don't mix rarities.")
Exemplo n.º 15
0
def c(u):import re;q=re.findall(r"\b['\-\w]+\b",u.lower());Q=q.count;D=[*map(Q,{*q})];return['',max(q,key=Q)][1in map(D.count,D)]

def c2(u):import re;q=''.join([i for i in u.lower()if i in[*map(chr,range(97,123)),*"'- "]]).split();Q=q.count;D=[*map(Q,{*q})];return['',max(q,key=Q)][1in map(D.count,D)]
Exemplo n.º 16
0
async def recipe(ctx, *, request: str):
    """Gives listed combinations to make single crew OR gives listed combinations including component crew member to make result crew member"""
    if request.lower() == 'help' or request.lower() == 'names':
        await ctx.send(
            "Names for prestige results are: " +
            lined_string(all_prestige_results) +
            "** = confirmed since December update\n# = rumored\nunmarked = NOT confirmed since December update"
        )
        return
    if ',' in request:
        names = request.lower().split(',')
        if names[1][0] == ' ':
            names[1] = names[1][1:]
    else:  #This will handle single name requests
        result = []
        for combo in prestiges:  #Find all prestige combinations that generate the request
            if fuzz.partial_ratio(request.lower(),
                                  prestiges[combo]) > search_threshold:
                result.append("%s = %s" % (
                    ([combo.title().split('_')][0]), prestiges[combo].title()))
        if result == []:
            unique_check = process.extractOne(request,
                                              uniques,
                                              scorer=fuzz.partial_ratio)
            if unique_check[1] > search_threshold:
                await ctx.send(
                    "%s was parsed as %s which is a unique. Since uniques are obtainable through mineral draws, prestige recipes including elite crew are not recorded."
                    % (request, unique_check[0]))
                return
            await ctx.send("There are no recorded recipes for %s" %
                           (request.title()) + source_check)
            return
        else:
            phrase = "These combinations are listed as potentially making %s:" % request.title(
            ) + lined_string(
                result
            ) + "\nConsider double checking your chosen recipe with ?prestige or the spreadsheet" + "\n** = confirmed since December update\n# = rumored\nunmarked = NOT confirmed since December update"
            while len(phrase) > 1950:
                await ctx.send(phrase[:phrase.find('[', 1800)] + "```")
                phrase = "```" + phrase[phrase.find('[', 1800):]
            await ctx.send(phrase)
            return
    result = []
    for combo in prestiges:  #This tree will handle prospective parent/child combinations
        if prestiges[combo] and fuzz.partial_ratio(
                names[0], prestiges[combo]
        ) > search_threshold:  #names[0] is the child/product here. This yields a list of all recipes making the child/product
            result.append("%s = %s" %
                          (([combo.split('_')][0]), prestiges[combo])
                          )  #entries in result will be the full combination
    result = [
        x.title() for x in result
        if fuzz.partial_ratio(names[1], x) > search_threshold
    ]  #Take only entries which contain the parent/reagent, names[1]
    if not result:  #If no entries contained the prevoius parent/reagent, names[1]...
        for combo in prestiges:  #try it the other way around with names[1] as the child/product
            if prestiges[combo] and fuzz.partial_ratio(
                    names[1], prestiges[combo]
            ) > search_threshold:  #names[1] is the child here
                result.append("%s = %s" %
                              (([combo.split('_')][0]), prestiges[combo]))
        result = [
            x.title() for x in result
            if fuzz.partial_ratio(names[0], x) > search_threshold
        ]  #Take only entries which contain the parent/reagent, names[0]
        if not result:
            await ctx.send("I see no relation between %s and %s" %
                           (names[0].title(), names[1].title()) + source_check)
            return
        else:
            phrase = "According to records, pertinent combinations between %s and %s are as follows:" % (
                names[0].title(), names[1].title()
            ) + lined_string(
                sorted(set([x.title() for x in result]))
            ) + "Remember, only Legendary combinations are guaranteed by Savy" + "\n** = confirmed since December update\n# = rumored\nunmarked = NOT confirmed since December update"
            while len(phrase) > 1950:
                await ctx.send(phrase[:phrase.find('[', 1800)] + "```")
                phrase = "```" + phrase[phrase.find('[', 1800):]
            await ctx.send(phrase)
            return
    else:
        phrase = "According to records, pertinent combinations between %s and %s are as follows:" % (
            names[0].title(), names[1].title()
        ) + lined_string(
            sorted(set([x.title() for x in result]))
        ) + "Remember, only Legendary combinations are guaranteed by Savy" + "\n** = confirmed since December update\n# = rumored\nunmarked = NOT confirmed since December update"
        while len(phrase) > 1950:
            await ctx.send(phrase[:phrase.find('[', 1800)] + "```")
            phrase = "```" + phrase[phrase.find('[', 1800):]
        await ctx.send(phrase)
        return
Exemplo n.º 17
0
async def prestige(ctx, *, request: str):
    """Returns data on prestige results for the two crew members entered as input"""
    if ',' in request:
        names = request.lower().split(',')
    else:  #If there's only one name, this tree will handle it. It will try to give all receipes for the one crew member
        result = []
        for combo in prestiges:
            if prestiges[combo] and process.extractOne(
                    request.lower(),
                    combo.lower().split('_'),
                    scorer=fuzz.partial_ratio)[1] > search_threshold:
                result.append("%s = %s" % (
                    ([combo.title().split('_')][0]), prestiges[combo].title()))
        if not result:
            legendary_check = process.extractOne(request,
                                                 legendaries,
                                                 scorer=fuzz.partial_ratio)
            if legendary_check[1] > search_threshold:
                await ctx.send(
                    "%s was parsed as %s which is a legendary crew. Currently, legendary is the highest tier of crew, and there are no combinations which use legendary crew."
                    % (request, legendary_check[0]))
                return
            await ctx.send(
                "Either I don't understand, or there are no known recipes including %s"
                % request + source_check)
            return
        else:
            short = sorted(
                set([
                    x for x in hero + epic + unique
                    if x[0] and fuzz.partial_ratio(
                        request.lower(), x[0].lower()) > search_threshold
                ][0][1:])
            )  #will return the list which has the target in the 0th position, a column or row in the spreadsheet
            phrase = "%s is listed as being used in:" % (
                request
            ) + lined_string(
                short
            ) + "\nFull recipes are as follows:\n" + lined_string(
                sorted(set([x.title() for x in result]))
            ) + "** = confirmed since December update\n# = rumored\nunmarked = NOT confirmed since December update"
            while len(phrase) > 1950:
                await ctx.send(phrase[:phrase.find('[', 1800)] + "```")
                phrase = "```" + phrase[phrase.find('[', 1800):]
            await ctx.send(phrase)
            return
    key_1 = process.extractOne(request,
                               prestiges.keys(),
                               scorer=fuzz.partial_ratio)[0]
    if prestiges[key_1]:
        result_1 = prestiges[key_1].title()
    else:
        result_1 = "Unlisted"
    key_2 = process.extractOne(names[1] + names[0],
                               prestiges.keys(),
                               scorer=fuzz.partial_ratio)[0]
    if prestiges[key_2]:
        result_2 = prestiges[key_2].title()
    else:
        result_2 = "Unlisted"
    phrase = "%s was parsed as %s which yields:```\n%s```\n%s yields:\n```\n%s```" % (
        request, key_1, result_1, key_2, result_2
    ) + "** = confirmed since December update\n# = rumored\nunmarked = NOT confirmed since December update"
    await ctx.send(phrase)
Exemplo n.º 18
0
async def stats(ctx, *, request: str):
    """Provides stat readouts for requested crew"""
    initial_request = request
    if request.lower() == 'help':
        await ctx.send(
            "Give a crew name or a crew name and a stat separated by a comma. All stats will be given if no specific stat is provided. Valid names can be found with ?stat names. Valid stats are ```gender, race, hp, pilot, attack, fire_resistance, repair, weapon, shield, engine, research, walking_speed, running_speed, rarity, progression, xp, special_type, special, training, and equipment.```"
        )
        return
    if request.lower() == 'equip' or request.lower() == 'equipment':
        await ctx.send("```%s```" % (equipment_loadouts))
        return
    if request.lower() == 'names':
        await ctx.send("Valid names are: ```%s```" % (crew.keys()))
        return
    if ',' in request:
        request = request.lower().split(',')
    else:
        request = process.extractOne(request,
                                     crew.keys(),
                                     scorer=fuzz.partial_ratio)[0]
        phrase = "%s was parsed as %s\n" % (
            initial_request, request.title()
        ) + "```Name: %s \nGender: %s\nRace: %s \nHP: %s \nPilot: %s \nAttack: %s \nFire Resistance: %s \nRepair: %s \nWeapon: %s \nShield: %s \nEngine: %s \nResearch: %s \nWalking Speed: %s \nRunning Speed: %s\nRarity: %s \nProgression: %s \nXP: %s \nSpecial Type: %s \nSpecial: %s \nTraining: %s \nEquipment: %s - %s```" % (
            getattr(crew[request],
                    metrics[0]).title(), getattr(crew[request], metrics[1]),
            getattr(crew[request],
                    metrics[2]), getattr(crew[request], metrics[3]),
            getattr(crew[request],
                    metrics[4]), getattr(crew[request], metrics[5]),
            getattr(crew[request],
                    metrics[6]), getattr(crew[request], metrics[7]),
            getattr(crew[request],
                    metrics[8]), getattr(crew[request], metrics[9]),
            getattr(crew[request],
                    metrics[10]), getattr(crew[request], metrics[11]),
            getattr(crew[request],
                    metrics[12]), getattr(crew[request], metrics[13]),
            getattr(crew[request],
                    metrics[14]), getattr(crew[request], metrics[15]),
            getattr(crew[request],
                    metrics[16]), getattr(crew[request], metrics[17]),
            getattr(crew[request],
                    metrics[18]), getattr(crew[request], metrics[19]),
            getattr(crew[request], metrics[20]), equipment_loadouts[int(
                getattr(crew[request], metrics[20]))])
        await ctx.send(phrase)
        return
    if request[1][0] == ' ':
        request[1] = request[1][1:]
    if request[0].lower() == 'equip' or request[0].lower() == 'equipment':
        try:
            await ctx.send("Loadout %s is for ```%s```" %
                           (request[1], equipment_loadouts[int(request[1])]))
            return
        except:
            await ctx.send("I don't know how you got here")
            return
    try:
        await ctx.send("%s's %s is: %s" %
                       (request[0].title(), request[1],
                        getattr(crew[request[0]], request[1])))
        if request[1].lower == 'equip' or request[1].lower() == 'equipment':
            await ctx.send("```%s```" % (equipment_loadouts[int(
                getattr(crew[request[0]], request[1]))]))
            return
    except:
        pass
    crew0 = process.extractOne(request[0],
                               crew.keys(),
                               scorer=fuzz.partial_ratio)
    crew1 = process.extractOne(request[1],
                               crew.keys(),
                               scorer=fuzz.partial_ratio)
    if crew0[1] > search_threshold and crew1[1] > search_threshold:
        crew0 = crew0[0]
        crew1 = crew1[0]
        phrase = "%s and %s were parsed as %s and %s\nAs compared to %s, %s has\n" % (
            request[0], request[1], crew0, crew1, crew1, crew0
        ) + "```%s - %s\nHP: %s \nPilot: %s \nAttack: %s \nFire Resistance: %s \nRepair: %s \nWeapon: %s \nShield: %s \nEngine: %s \nResearch: %s \nWalking Speed: %s \nRunning Speed: %s\nSpecial Type: %s \nSpecial: %s \nTraining : %s \nEquipment: %s```" % (
            crew0.title(), crew1.title(), crew[crew0].hp - crew[crew1].hp,
            crew[crew0].pilot - crew[crew1].pilot,
            round(crew[crew0].attack - crew[crew1].attack, 4),
            round(crew[crew0].fire_resistance - crew[crew1].fire_resistance,
                  5), round(crew[crew0].repair - crew[crew1].repair,
                            4), crew[crew0].weapon - crew[crew1].weapon,
            crew[crew0].shield - crew[crew1].shield, crew[crew0].engine -
            crew[crew1].engine, crew[crew0].research - crew[crew1].research,
            crew[crew0].walking_speed - crew[crew1].walking_speed,
            crew[crew0].running_speed - crew[crew1].running_speed,
            str(crew[crew0].special_type) + " vs. " +
            str(crew[crew1].special_type),
            str(crew[crew0].special) + " vs. " + str(crew[crew1].special),
            crew[crew0].training - crew[crew1].training,
            equipment_loadouts[int(crew[crew0].equipment)] + " vs. " +
            equipment_loadouts[int(crew[crew1].equipment)])
        await ctx.send(phrase)
        return