├── .gitignore ├── LICENSE.txt ├── README.rst ├── ptcaccount ├── __init__.py ├── accountcreator.py ├── console.py └── ptcexceptions.py ├── requirements.txt └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__/ 2 | *.egg-info/ 3 | venv*/ 4 | *.pyc 5 | *.pyo 6 | *.ini 7 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 James Payne. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 7 | 8 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 9 | 10 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 11 | 12 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 13 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | Pokemon Trainer Club Account Creator v1.2.1 2 | =========================================== 3 | 4 | Description 5 | ----------- 6 | Automatically creates Pokemon Trainer Club accounts. When fully implemented, will allow for specifying the specific values used or can randomly generate usernames, passwords, and emails. A possible future goal might be to create a temporary email to receive and validate the confirmation email. 7 | 8 | Use 9 | --- 10 | **Command line interface:** 11 | 12 | After installing the package run 'ptc' from the terminal to create a new account. 13 | Optional parameters include *--username*, *--password*, and *--email*. 14 | Use *--help* for command line interface help. 15 | 16 | Example 1 (Create entirely random new account):: 17 | 18 | > ptc 19 | Created new account: 20 | Username: dGXJXnAzxqmjbaP 21 | Password: yUbiAgcXhBrEwHk 22 | Email : TVKzlu1AcW@6yxi6.com 23 | 24 | Example 2 (Create a new account with specified parameters):: 25 | 26 | > ptc --username=mycustomusername --password=hunter2 --email=verifiable@lackmail.ru 27 | Created new account: 28 | Username: mycustomusername 29 | Password: hunter2 30 | Email : verifiable@lackmail.ru 31 | 32 | Extra Options: 33 | 34 | - *--email-tag*: Add the username as a tag to the email (e.g. address+username@gmail.com). 35 | 36 | **As package:** 37 | 38 | Import the *ptcaccount* package to create new accounts in your own scripts:: 39 | 40 | >>> from ptcaccount import random_account 41 | >>> random_account() 42 | {'username': 'dGXJXnAzxqmjbaP', 'password': 'yUbiAgcXhBrEwHk', 'email': 'TVKzlu1AcW@6yxi6.com', 'provider': 'ptc'} 43 | 44 | 45 | Installation 46 | ------------ 47 | Supports Python 2 and 3. 48 | 49 | Install from Github using pip:: 50 | 51 | pip install git+https://github.com/jepayne1138/PTCAccount.git@v1.2.1 52 | -------------------------------------------------------------------------------- /ptcaccount/__init__.py: -------------------------------------------------------------------------------- 1 | from ptcaccount.accountcreator import * 2 | -------------------------------------------------------------------------------- /ptcaccount/accountcreator.py: -------------------------------------------------------------------------------- 1 | from six.moves import range 2 | import random 3 | import string 4 | # urllib imports supporting Python 2 and 3 5 | try: 6 | # Python 3 7 | from urllib.parse import urlencode 8 | except ImportError: 9 | # Python 2 10 | from urllib import urlencode 11 | 12 | import requests 13 | 14 | from ptcaccount.ptcexceptions import * 15 | 16 | 17 | __all__ = [ 18 | 'create_account', 19 | 'random_account', 20 | 'PROVIDER', 21 | 'USERNAME', 22 | 'PASSWORD', 23 | 'EMAIL' 24 | ] 25 | 26 | # Constants defining the keys of the returned account dictionary 27 | PROVIDER = 'provider' 28 | USERNAME = 'username' 29 | PASSWORD = 'password' 30 | EMAIL = 'email' 31 | _PTC_PROVIDER = 'ptc' # Account provider (APIs take 'ptc' or 'google') 32 | 33 | 34 | # The base URL for Pokemon Trainer Club 35 | _BASE_URL = 'https://club.pokemon.com/us/pokemon-trainer-club' 36 | 37 | # Account creation validation is done by checking the response URLs 38 | # The following are control flow URL constants 39 | _SUCCESS_DESTS = ( 40 | 'https://club.pokemon.com/us/pokemon-trainer-club/parents/email', # This initially seemed to be the proper success redirect 41 | 'https://club.pokemon.com/us/pokemon-trainer-club/sign-up/', # but experimentally it now seems to return to the sign-up, but still registers 42 | ) 43 | # As both seem to work, we'll check against both success destinations until I have I better idea for how to check success 44 | _DUPE_EMAIL_DEST = 'https://club.pokemon.com/us/pokemon-trainer-club/forgot-password?msg=users.email.exists' 45 | _BAD_DATA_DEST = 'https://club.pokemon.com/us/pokemon-trainer-club/parents/sign-up' 46 | 47 | 48 | class PTCSession(requests.Session): 49 | 50 | """"A Session subclass handling creating, sending, & validating requests 51 | 52 | A likely unnecessary subclass of requests.Session, but I thought it 53 | helped to clean up the code. 54 | """ 55 | 56 | def request(self, url, headers=None, data=None, resp_code=None, **kwargs): 57 | """ 58 | Creates, sends, and validates a request for this session. 59 | 60 | If data parameter is provided, the request will be POST, otherwise 61 | a GET request is sent 62 | 63 | If a specific response status code is 64 | expected, set the resp_code parameter and the status code of the 65 | response will be validated after sending the request. If the status 66 | codes doesn't match, an exception is raised. 67 | 68 | Args: 69 | url (str): URL to send. 70 | headers (dict, optional): Headers to send. Defaults to {}. 71 | data (dict, optional): Data for a POST request. Defaults to {}. 72 | resp_code (int, optional): Check if this status code was returned 73 | upon receiving a response. If no desired code is given, no 74 | check will be made to validate the response status_code. 75 | Defaults to None. 76 | **kwargs: Keyword arguments passed to the Request object. 77 | 78 | Returns: 79 | requests.Response: The Response object for the sent request. 80 | 81 | Raises: 82 | PTCInvalidStatusCodeException: If a desired response code was 83 | provided (resp_code), raise this exception if the actual 84 | response status codes does not match the desired code. 85 | """ 86 | # Set headers to an empty dict if no argument provided 87 | headers = {} if headers is None else headers 88 | 89 | # Encode the data dict if provided 90 | if isinstance(data, dict): 91 | data = urlencode(data, doseq=True) 92 | # If data provided, the request must be a POST method 93 | method = 'POST' if data else 'GET' 94 | 95 | # Create, prepare, and send the request 96 | req = requests.Request(method, url, data=data, **kwargs) 97 | prepped = self.prepare_request(req) 98 | prepped.headers.update(headers) 99 | resp = self.send(prepped) 100 | 101 | # Validate the status_code if a desired code was given 102 | if resp_code is not None and resp.status_code != resp_code: 103 | raise PTCInvalidStatusCodeException(str(resp.status_code)) 104 | 105 | # Return the Response object 106 | return resp 107 | 108 | 109 | def _random_string(length=15): 110 | """Generate a random alpha-numeric string of the given length 111 | 112 | Args: 113 | length (int, optional): Length of the string to randomly generate. 114 | Defaults to 15. 115 | 116 | Returns: 117 | str: String of the desired length consiting of upper, lower, and 118 | numeric characters. 119 | """ 120 | return ''.join( 121 | [random.choice(string.ascii_letters + string.digits) for _ in range(length)] 122 | ) 123 | 124 | 125 | def _random_email(local_length=10, sub_domain_length=5, top_domain='.com'): 126 | """Generate a random email-like string 127 | 128 | Generates a random email-like string (i.e. local@subdomain.domain). 129 | The length of both the local section and sub-domain section can be 130 | modified, and a different top-level domain can be set. 131 | 132 | Args: 133 | local_length (int, optional): Length of the local portion of the fake 134 | email. Defaults to 10. 135 | sub_domain_length (int, optional): Length of the sub-domain portion of 136 | the fake email. Defaults to 5. 137 | top_domain (str, optional): String to append to the end of the fake 138 | email as the top-level domain. Defaults to '.com' 139 | 140 | Returns: 141 | str: Random email-like string. 142 | """ 143 | return '{local}@{sub_domain}{top_domain}'.format( 144 | local=_random_string(local_length), 145 | sub_domain=_random_string(sub_domain_length), 146 | top_domain=top_domain, 147 | ) 148 | 149 | 150 | def _validate_password(password): 151 | """Validates that the password can be used to create a PTC account 152 | 153 | As currently the only requirement I am aware of is a length restriction, 154 | this only checks that the give password string is between 6 and 15 155 | characters long. If I determine any other restrictions, they can be 156 | added here later. 157 | 158 | Args: 159 | password (str, optional): Password to be validated. 160 | 161 | Returns: 162 | bool: True if the password is valid. (Does not return false, rather 163 | raise exception with description of invalid nature.) 164 | 165 | Raises: 166 | PTCInvalidPasswordException: If the given password is not a valid 167 | password that can be used to make an account. (Currently just 168 | validates length, so this means the given password was not between 169 | 6 and 15 characters long.) 170 | """ 171 | # Check that password length is between 6 and 15 characters long 172 | if len(password) < 6 or len(password) > 15: 173 | raise PTCInvalidPasswordException('Password must be between 6 and 15 characters.') 174 | return True 175 | 176 | 177 | def _tag_email(email_address, tag): 178 | """Add a plus sign and the tag before the first at sign in the email 179 | 180 | Args: 181 | email_address (str): Email address tag is to be added to. 182 | tag (str): Tag to add after the plus sign before first at sign. 183 | 184 | Returns: 185 | str: Email with the tag added. 186 | """ 187 | return email_address.replace('@', '+{}@'.format(tag), 1) 188 | 189 | 190 | def create_account(username, password, email): 191 | """Creates a new Pokemon Trainer Club account 192 | 193 | Creates a new PTC account with the given username, password and email. 194 | Currently sets the following account settings: 195 | - Date of birth: 1970-01-01 196 | - Country: US 197 | - Public profile: False 198 | - Screen name: '' 199 | 200 | Args: 201 | username (str): Username for the PTC account 202 | password (str): Password for the PTC account 203 | email (str): Email for the PtC account 204 | 205 | Returns: 206 | bool: True if the account was successfully created. (Should not ever 207 | return false, rather raise exceptions detailing type of failure.) 208 | 209 | Raises: 210 | PTCInvalidNameException: If the given username is already in use. 211 | PTCInvalidPasswordException: If the given password is not a valid 212 | password that can be used to make an account. (Currently just 213 | validates length, so this means the given password was not between 214 | 6 and 15 characters long.) 215 | PTCInvalidEmailException: If the given email was either in an invalid 216 | format (i.e. not local@subdomain.domain) or the email is already 217 | registered to an existing account. 218 | PTCInvalidStatusCodeException: If an invalid status code was received 219 | at any time. (Server or underlying code issue; try again and submit 220 | bug report on continues failure if creation works in browser.) 221 | """ 222 | # Validate a user given password 223 | if password is not None: 224 | _validate_password(password) 225 | 226 | # Set up the session 227 | session = PTCSession() 228 | 229 | successfully_created = False 230 | while not successfully_created: 231 | try: 232 | # (Emulates navigating to the sign-up age verification page) 233 | session.request( 234 | url='{base_url}/parents/sign-up'.format(base_url=_BASE_URL), 235 | headers={ # No headers required 236 | 'Host': 'club.pokemon.com', 237 | 'Connection': 'keep-alive', 238 | 'Upgrade-Insecure-Requests': '1', 239 | 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36', 240 | 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', 241 | 'Accept-Encoding': 'gzip, deflate, sdch, br', 242 | 'Accept-Language': 'en-US,en;q=0.8', 243 | }, 244 | resp_code=200 245 | ) 246 | 247 | # Post request submitting date of birth and country 248 | session.request( 249 | url='{base_url}/sign-up/'.format(base_url=_BASE_URL), 250 | headers={ # Content-Type and Referer headers are required 251 | 'Host': 'club.pokemon.com', 252 | 'Cache-Control': 'max-age=0', 253 | 'Origin': 'https://club.pokemon.com', 254 | 'Upgrade-Insecure-Requests': '1', 255 | 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36', 256 | 'Content-Type': 'application/x-www-form-urlencoded', 257 | 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', 258 | 'Referer': '{base_url}/sign-up/'.format(base_url=_BASE_URL), 259 | 'Accept-Encoding': 'gzip, deflate, br', 260 | 'Accept-Language': 'en-US,en;q=0.8' 261 | }, 262 | data={ 263 | 'csrfmiddlewaretoken': session.cookies.get_dict()['csrftoken'], 264 | 'dob': '1970-01-01', 265 | 'country': 'US', 266 | }, 267 | resp_code=200 268 | ) 269 | 270 | # Post request submitting account information 271 | resp = session.request( 272 | url='{base_url}/parents/sign-up'.format(base_url=_BASE_URL), 273 | headers={ # Content-Type and Referer headers are required 274 | 'Host': 'club.pokemon.com', 275 | 'Cache-Control': 'max-age=0', 276 | 'Origin': 'https://club.pokemon.com', 277 | 'Upgrade-Insecure-Requests': '1', 278 | 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36', 279 | 'Content-Type': 'application/x-www-form-urlencoded', 280 | 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', 281 | 'Referer': 'https://club.pokemon.com/us/pokemon-trainer-club/parents/sign-up', 282 | 'Accept-Encoding': 'gzip, deflate, br', 283 | 'Accept-Language': 'en-US,en;q=0.8' 284 | }, 285 | data={ 286 | 'csrfmiddlewaretoken': session.cookies.get_dict()['csrftoken'], 287 | 'username': username, 288 | 'password': password, 289 | 'confirm_password': password, 290 | 'email': email, 291 | 'confirm_email': email, 292 | 'public_profile_opt_in': 'False', 293 | 'screen_name': '', 294 | 'terms': 'on', 295 | }, 296 | resp_code=200 297 | ) 298 | 299 | # Indicates that we created the account and can exit the retry loop 300 | successfully_created = True 301 | except PTCInvalidStatusCodeException: 302 | print("[-] Received invalid status code, retrying ...") 303 | 304 | # Validate response 305 | return _validate_response(resp) 306 | 307 | 308 | def _validate_response(resp): 309 | """Validate final request response to determine if account was created 310 | 311 | Args: 312 | resp (requests.Response): Response instance from sending a requests 313 | 314 | Returns: 315 | bool: True if the account was successfully created. (Should not ever 316 | return false, rather raise exceptions detailing type of failure.) 317 | 318 | Raises: 319 | PTCInvalidNameException: If the given username is already in use. 320 | PTCInvalidPasswordException: If the given password is not a valid 321 | password that can be used to make an account. (Currently just 322 | validates length, so this means the given password was not between 323 | 6 and 15 characters long.) 324 | PTCInvalidEmailException: If the given email was either in an invalid 325 | format (i.e. not local@subdomain.domain) or the email is already 326 | registered to an existing account. 327 | PTCInvalidStatusCodeException: If an invalid status code was received 328 | at any time. (Server or underlying code issue; try again and submit 329 | bug report on continues failure if creation works in browser.) 330 | """ 331 | if resp.url in _SUCCESS_DESTS: 332 | return True 333 | elif resp.url == _DUPE_EMAIL_DEST: 334 | raise PTCInvalidEmailException('Email already in use.') 335 | elif resp.url == _BAD_DATA_DEST: 336 | if 'Enter a valid email address.' in resp.text: 337 | raise PTCInvalidEmailException('Invalid email.') 338 | else: 339 | raise PTCInvalidNameException('Username already in use.') 340 | else: 341 | raise PTCException('Generic failure. User was not created.') 342 | return False # Should never hit here 343 | 344 | 345 | def random_account(username=None, password=None, email=None, email_tag=False): 346 | """Crate a random Pokemon Trainer Club account 347 | 348 | Creates a new account with random username, password, and email. 349 | If any of those parameters are given, use them instead of creating 350 | a random replacement. 351 | 352 | If a password is given, it must be valid, and an exception will be 353 | raised if the password is not acceptable. 354 | 355 | New random strings will be generated for username and email on a failure 356 | so that eventually a new account will be successfully created. However, 357 | if a specific username or email was given and account creation fails, 358 | a new string will not be generated as it assumes the user wanted to use 359 | that specific value. Instead, and exception is raised indicating the 360 | reason for account creation failure. 361 | 362 | Args: 363 | username (str, optional): Specific username for the new account. 364 | Defaults to a random alpha-numeric string. 365 | password (str, optional): Specific password for the new account. 366 | Defaults to a random alpha-numeric string. 367 | email (str, optional): Specific email for the new account. Defaults 368 | to a randomly generated email-like string. 369 | email_tag (bool, optional): The username should be added as a tag 370 | to the email address. Defaults to False. 371 | 372 | Returns: 373 | Dict[str, str]: A dict of the new account information, containing the 374 | provider ('ptc'), username, password, and email. Access using the 375 | exposed constants PROVIDER, USERNAME, PASSWORD, and EMAIL. 376 | 377 | Raises: 378 | PTCInvalidNameException: If the given username is already in use. 379 | PTCInvalidPasswordException: If the given password is not a valid 380 | password that can be used to make an account. (Currently just 381 | validates length, so this means the given password was not between 382 | 6 and 15 characters long.) 383 | PTCInvalidEmailException: If the given email was either in an invalid 384 | format (i.e. not local@subdomain.domain) or the email is already 385 | registered to an existing account. 386 | PTCInvalidStatusCodeException: If an invalid status code was received 387 | at any time. (Server or underlying code issue; try again and submit 388 | bug report on continues failure if creation works in browser.) 389 | """ 390 | try_username = _random_string() if username is None else str(username) 391 | password = _random_string() if password is None else str(password) 392 | try_email = _random_email() if email is None else str(email) 393 | 394 | account_created = False 395 | while not account_created: 396 | # Add tag in loop so that it is update if email or username changes 397 | if email_tag: 398 | try_email = _tag_email(try_email, try_username) 399 | 400 | # Attempt to create the new account 401 | try: 402 | account_created = create_account( 403 | try_username, password, try_email 404 | ) 405 | except PTCInvalidNameException: 406 | # If no username was provided, create new username and try again 407 | if username is None: 408 | try_username = _random_string() 409 | else: 410 | # If username was provided, re-raise the exception for bad name 411 | raise 412 | except PTCInvalidEmailException: 413 | if email is None: 414 | try_email = _random_email() 415 | elif email_tag and username is None: 416 | # If the bad email has a tag of a random username, 417 | # re-generate a new username and try again 418 | try_username = _random_string() 419 | else: 420 | # If email was provided, re-raise the exception for bad email 421 | raise 422 | 423 | # Return the username, password, and email of the new account 424 | return { 425 | PROVIDER: _PTC_PROVIDER, 426 | USERNAME: try_username, 427 | PASSWORD: password, 428 | EMAIL: try_email, 429 | } 430 | -------------------------------------------------------------------------------- /ptcaccount/console.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import sys 3 | 4 | from ptcaccount import * 5 | from ptcaccount.ptcexceptions import * 6 | 7 | 8 | def parse_arguments(args): 9 | """Parse the command line arguments for the console commands. 10 | 11 | Args: 12 | args (List[str]): List of string arguments to be parsed. 13 | 14 | Returns: 15 | Namespace: Namespace with the parsed arguments. 16 | """ 17 | parser = argparse.ArgumentParser( 18 | description='Pokemon Trainer Club Account Creator' 19 | ) 20 | parser.add_argument( 21 | '-u', '--username', type=str, default=None, 22 | help='Username for the new account (defaults to random string).' 23 | ) 24 | parser.add_argument( 25 | '-p', '--password', type=str, default=None, 26 | help='Password for the new account (defaults to random string).' 27 | ) 28 | parser.add_argument( 29 | '-e', '--email', type=str, default=None, 30 | help='Email for the new account (defaults to random email-like string).' 31 | ) 32 | parser.add_argument( 33 | '-m', '--multiple', type=int, default=1, 34 | help='Create multiple accounts at once (defaults to 1)' 35 | ) 36 | parser.add_argument( 37 | '--compact', action='store_true', 38 | help='Compact the output to "username:password"' 39 | ) 40 | parser.add_argument( 41 | '--email-tag', action='store_true', 42 | help='Add the username as a tag to the email (i.e addr+tag@mail.com).' 43 | ) 44 | return parser.parse_args(args) 45 | 46 | 47 | def entry(): 48 | """Main entry point for the package console commands""" 49 | args = parse_arguments(sys.argv[1:]) 50 | try: 51 | print('Creating new account(s):') 52 | for _ in range(args.multiple): 53 | # Create the random account 54 | account_info = random_account( 55 | args.username, args.password, args.email, args.email_tag 56 | ) 57 | 58 | if args.compact: 59 | print('{}:{}'.format(account_info[USERNAME], account_info[PASSWORD])) 60 | else: 61 | print(' Username: {}'.format(account_info[USERNAME])) 62 | print(' Password: {}'.format(account_info[PASSWORD])) 63 | print(' Email : {}'.format(account_info[EMAIL])) 64 | print('\n') 65 | 66 | 67 | # Handle account creation failure exceptions 68 | except PTCInvalidPasswordException as err: 69 | print('Invalid password: {}'.format(err)) 70 | except (PTCInvalidEmailException, PTCInvalidNameException) as err: 71 | print('Failed to create account! {}'.format(err)) 72 | except PTCException as err: 73 | print('Failed to create account! General error: {}'.format(err)) 74 | -------------------------------------------------------------------------------- /ptcaccount/ptcexceptions.py: -------------------------------------------------------------------------------- 1 | __all__ = [ 2 | 'PTCException', 3 | 'PTCInvalidStatusCodeException', 4 | 'PTCInvalidNameException', 5 | 'PTCInvalidEmailException', 6 | 'PTCInvalidPasswordException', 7 | ] 8 | 9 | 10 | class PTCException(Exception): 11 | """Base exception for all PTC Account exceptions""" 12 | pass 13 | 14 | 15 | class PTCInvalidStatusCodeException(Exception): 16 | """Base exception for all PTC Account exceptions""" 17 | pass 18 | 19 | 20 | class PTCInvalidNameException(PTCException): 21 | """Username already in use""" 22 | pass 23 | 24 | 25 | class PTCInvalidEmailException(PTCException): 26 | """Email invalid or already in use""" 27 | pass 28 | 29 | 30 | class PTCInvalidPasswordException(PTCException): 31 | """Password invalid""" 32 | pass 33 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | requests[security]==2.10.0 2 | six==1.10.0 3 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | from io import open 3 | from setuptools import setup 4 | 5 | DIST_NAME = 'PTCAccount' 6 | VERSION = 'v1.2.2' 7 | AUTHOR = 'James Payne' 8 | EMAL = 'jepayne1138@gmail.com' 9 | GITHUB_USER = 'jepayne1138' 10 | GITHUB_URL = 'https://github.com/{GITHUB_USER}/{DIST_NAME}'.format(**locals()) 11 | 12 | # Get the long description from the README file 13 | setup_dir = os.path.dirname(os.path.realpath(__file__)) 14 | with open(os.path.join(setup_dir, 'README.rst'), encoding='utf-8') as readme: 15 | long_description = readme.read() 16 | 17 | setup( 18 | name=DIST_NAME, 19 | packages=['ptcaccount'], 20 | version=VERSION, 21 | description='Automatic creation of Pokemon Trainer Club accounts.', 22 | author=AUTHOR, 23 | author_email=EMAL, 24 | url=GITHUB_URL, 25 | license='BSD-new', 26 | download_url='{GITHUB_URL}/tarball/{VERSION}'.format(**locals()), 27 | keywords='', 28 | install_requires=[ 29 | 'requests[security]==2.10.0', 30 | 'six==1.10.0', 31 | ], 32 | classifiers=[ 33 | 'Programming Language :: Python', 34 | 'Programming Language :: Python :: 2.7', 35 | 'Programming Language :: Python :: Implementation :: CPython', 36 | 'License :: OSI Approved :: BSD License', 37 | ], 38 | entry_points={ 39 | 'console_scripts': [ 40 | 'ptc = ptcaccount.console:entry', 41 | ], 42 | } 43 | ) 44 | --------------------------------------------------------------------------------