import mwapi

def validate_username(user_name, lang):
    Normalize a single user name via the wikimedia API
    :param user_name: the user-name to normalize
    :param lang: the language to make an api session if none supplied
    :return: dict like {'user_id': 123, 'name': 'canonical username'}
    mwapi_session = mwapi.Session(f'https://{lang}', user_agent="CivilServant Username Normalizer <>")
    user_name_resp = mwapi_session.get(action='query', list='users', ususers=user_name)
        name_id = user_name_resp['query']['users'][0]
        return {"valid":True, "user_id": name_id['userid'], "canonical_user_name": name_id['name']}
    except Exception as e:
        e = "User name not found" if isinstance(e, KeyError) else e
        return {"valid":False, "error":e}

you can provide a string, and the canonical name might be different, wikimedia capitlizes the first letter

validate_username('maximilianklein', 'en')
{'valid': True, 'user_id': 13023703, 'canonical_user_name': 'Maximilianklein'}

of course exact matches work

validate_username('Maximilianklein', 'en')
{'valid': True, 'user_id': 13023703, 'canonical_user_name': 'Maximilianklein'}

so to does the convention "User:"

validate_username('User:Maximilianklein', 'en')
{'valid': True, 'user_id': 13023703, 'canonical_user_name': 'Maximilianklein'}

Note that the language is important for user_ids

validate_username('User:Juliakamin', 'en')
{'valid': True, 'user_id': 33564818, 'canonical_user_name': 'Juliakamin'}

in french it's different

validate_username('User:Juliakamin', 'fr')
{'valid': True, 'user_id': 3113092, 'canonical_user_name': 'Juliakamin'}

Spaces or underscores

validate_username('Piano non troppo', 'en')
{'valid': True, 'user_id': 7723863, 'canonical_user_name': 'Piano non troppo'}

Should return the same

validate_username('Piano_non_troppo', 'en')
{'valid': True, 'user_id': 7723863, 'canonical_user_name': 'Piano non troppo'}

Invalid user names should return with "valid:False"

validate_username('doesnt exist user name', 'en')
{'valid': False, 'error': 'User name not found'}