<commit_before>from zinc_request_processor import ZincRequestProcessor
import sys
import json

WELCOME_BANNER = """
 ____      ____             __
|_  _|    |_  _|           [  |
  \ \  /\  / /.---.  .---.  | |  .--.   _ .--..--.  .---.
   \ \/  \/ // /__\\/ /'`\] | |/ .'`\ \[ `.-. .-. |/ /__\\
    \  /\  / | \__.,| \__.  | || \__. | | | | | | || \__.,
     \/  \/   '.__.''.___.'[___]'.__.' [___||__||__]'.__.'

                     _________
                    |  _   _  |
                    |_/ | | \_|.--.
                        | |  / .'`\ \
                       _| |_ | \__. |
                      |_____| '.__.'

            ________   _                   _
           |  __   _| (_)                 | |
           |_/  / /   __   _ .--.   .---. | |
              .'.' _ [  | [ `.-. | / /'`\]| |
            _/ /__/ | | |  | | | | | \__. |_|
           |________|[___][___||__]'.___.'(_)
"""

class ValidationHelpers(object):
    @classmethod
    def validate_number(klass, maximum, minimum=0):
        def validate(x):
            if (int(x) <= maximum and int(x) >= minimum):
                return True
            else:
                print "You must enter a number between %s and %s\n" % (minimum, maximum)
        return validate

    @classmethod
    def validate_boolean(klass):
        def validate(x):
            if (x == "y" or x == "n"):
                return True
            else:
                print "You must enter either 'y' or 'n'"
        return validate

    @classmethod
    def valid_credit_card(klass):
        def validate(card_number):
            digit_sum = 0
            num_digits = len(card_number)
            oddeven = num_digits & 1
            for count in range(0, num_digits):
                digit = int(card_number[count])
            if not (( count & 1 ) ^ oddeven ):
                digit = digit * 2
            if digit > 9:
                digit = digit - 9
            digit_sum += digit
            if ( (digit_sum % 10) == 0 ):
                return True
            else:
                print "Invalid credit card number"
        return validate

class ZincWizard(object):
    PROMPTS = {
        "product_variants": WELCOME_BANNER + "\nPlease please enter a product URL.",
        "product_quantity": "How many would you like to purchase? (Default: 1)",
        "select_product_variants": "This item comes in multiple variants. Please choose an option.",
        "select_shipping_methods": "This item has multiple shipping options. Please choose an option.",
        "security_code": "Please enter the CVV security code on your credit card.",
        "place_order": "Would you like to place this order? (y)/n",
        "gift": "Do you want this to be shipped as a gift? (y)/n",
        "shipping_address": {
            "start_message": "\nNow we'd like to get your shipping information.",
            "end_message": "\nYou've finished entering your shipping address!"
            },
        "address": {
            "first_name": "Please input your first name:",
            "last_name": "Please input your last name:",
            "address_line1": "Please input the first line of your shipping address:",
            "address_line2": "Please input the second line of your shipping address: (optional)",
            "city": "Please input your city:",
            "state": "Please input your state (e.g. CA, MA, etc.):",
            "zip_code": "Please input your zip code:",
            "country": "Please input your country (e.g. US):",
            "confirmation_message": "Is this your correct shipping address? (y)/n"
            },
        "billing_address" : {
            "start_message": "\nIs your billing address the same as your shipping address? (y)/n",
            "end_message": "\nYou've finished entering you billing address!"
            },
        "credit_card": {
            "start_message": "\nNow we'd like to get your credit card information.",
            "number": "Please input your credit card number",
            "expiration_month": "Please input your credit card expiration month (e.g. 03)",
            "expiration_year": "Please input your credit card expiration year (e.g. 2017)",
            "security_code": "Please input the CVV security code from your credit card",
            "end_message": "\nYou've finished entering your credit card information!"
            }
        }

    def __init__(self, options = None):
        self.options = (options if options is not None else {})
        self.response_data = {}
        self.security_code = None

    def start(self):
        self.get_product_variants(self.response_data)
        self.get_shipping_methods(self.response_data)
        self.get_store_card(self.response_data)
        self.get_review_order(self.response_data)
        self.get_place_order(self.response_data)

    def prompt(self, prompt, validation=None, max_attempts=3):
        attempts = 0
        while True:
            raw = raw_input(prompt + "\n")
            if (validation == None) or (validation != None and validation(raw)):
                return raw
            else:
                attempts += 1
                if attempts >= max_attempts:
                    print "You've reached the maximum number of attempts. Exiting!"
                    sys.exit()

    def prompt_boolean(self, prompt):
        result = self.prompt(prompt, ValidationHelpers.validate_boolean()).strip()
        if (result == "y" or result == ""):
            return True
        return False

    def get_product_variants(self, response_data):
        if "product_url" in self.options:
            product_url = self.options["product_url"]
        else:
            product_url = self.prompt(self.PROMPTS["product_variants"])

        print "\nProcessing request...\n"
        variants_response = ZincRequestProcessor.process("variant_options", {
                    "client_token": self.options["client_token"],
                    "retailer": self.options["retailer"],
                    "product_url": product_url
                    })
        response_data["variant_options_response"] = variants_response
        response_data["products"] = self.select_product_variants(variants_response)

    def get_shipping_methods(self, response_data):
        shipping_address = self.load_file_contents("shipping_address")
        print "\nProcessing request...\n"
        shipping_response = ZincRequestProcessor.process("shipping_methods", {
                    "client_token": self.options["client_token"],
                    "retailer": self.options["retailer"],
                    "products": response_data["products"],
                    "shipping_address": shipping_address
                })

        response_data["shipping_response"] = shipping_response
        response_data["shipping_address"] = shipping_address
        response_data["shipping_method_id"] = self.select_shipping_methods(shipping_response)

    def get_store_card(self, response_data):
        if "cc_token" in self.options and self.options["cc_token"] != None:
            response_data["cc_token"] = self.options["cc_token"]
        else:
            cc_data = self.load_file_contents("credit_card")
            billing_address = self.load_file_contents("billing_address")
            print "\nProcessing request...\n"
            store_card_response = ZincRequestProcessor.process("store_card", {
                        "client_token": self.options["client_token"],
                        "retailer": self.options["retailer"],
                        "billing_address": billing_address,
                        "number": cc_data["number"],
                        "expiration_month": cc_data["expiration_month"],
                        "expiration_year": cc_data["expiration_year"]
                    })

            response_data["store_card_response"] = store_card_response
            response_data["cc_token"] = store_card_response["cc_token"]

    def get_review_order(self, response_data):
        payment_method = {
                "cc_token": response_data["cc_token"],
                "security_code": self.get_security_code()
                }
        is_gift = self.get_is_gift()
        print "\nProcessing request...\n"
        review_order_response = ZincRequestProcessor.process("review_order", {
                    "client_token": self.options["client_token"],
                    "retailer": self.options["retailer"],
                    "products": response_data["products"],
                    "shipping_address": response_data["shipping_address"],
                    "is_gift": is_gift,
                    "shipping_method_id": response_data["shipping_method_id"],
                    "payment_method": payment_method,
                    "customer_email": "support@zinc.io"
                })

        response_data["review_order_response"] = review_order_response

    def get_place_order(self, response_data):
        self.print_price_components(response_data)
        if self.prompt_boolean(self.PROMPTS["place_order"]):
            print "\nProcessing request...\n"
            place_order_resonse = ZincRequestProcessor.process("place_order", {
                        "client_token": self.options["client_token"],
                        "place_order_key": response_data["review_order_response"]["place_order_key"]
                    })

            response_data["place_order_response"] = place_order_response
            print "HOORAY! You've successfully placed an order. Here are the details:\n"
            print "Amazon Order Id: %s" % place_order_response["merchant_order"]["merchant_order_id"]
            print "Total Price: %s" % place_order_response["price_components"]["total"]
            print place_order_response["shipping_method"]["name"] + ": " + place_order_response["shipping_method"]["description"]

    def print_price_components(self, response_data):
        components = response_data["review_order_response"]["price_components"]
        self.print_indent("Product Subtotal: %s" % self.format_price(components["subtotal"]))
        self.print_indent("Shipping Cost:    %s" % self.format_price(components["shipping"]))
        self.print_indent("Tax:              %s" % self.format_price(components["tax"]))
        if "gift_card" in components:
            self.print_indent("Gift Card:        %s" % self.format_price(components["gift_card"]))
        self.print_indent("Total:            %s" % self.format_price(components["total"]))

    def print_indent(self, value):
        print "    ", value

    def get_is_gift(self):
        if "gift" in self.options:
            return self.options["gift"]
        return self.prompt_boolean(self.PROMPTS["gift"])

    def get_security_code(self):
        if self.security_code != None:
            return self.security_code
        return self.prompt(self.PROMPTS["security_code"])

    def load_file_contents(self, filetype):
        if filetype in self.options and self.options[filetype] != None:
            with open(self.options[filetype], 'rb') as f:
                return json.loads(f.read())
        elif filetype == "shipping_address":
            print self.PROMPTS[filetype]["start_message"]
            return self.get_address(filetype)
        elif filetype == "billing_address":
            if self.prompt_boolean(self.PROMPTS[filetype]["start_message"]):
                return self.response_data["shipping_address"]
            else:
                return self.get_address(filetype)
        elif filetype == "credit_card":
            return self.get_credit_card_information()

    def get_credit_card_information(self):
        print self.PROMPTS["credit_card"]["start_message"]
        response = {}
        response["number"] = self.prompt(self.PROMPTS["credit_card"]["number"],
                ValidationHelpers.validate_credit_card())
        response["expiration_month"] = self.prompt(self.PROMPTS["credit_card"]["expiration_month"],
                ValidationHelpers.validate_number(12, 1))
        response["expiration_year"] = self.prompt(self.PROMPTS["credit_card"]["expiration_year"],
                ValidationHelpers.validate_number(2100, 2010))
        self.security_code = self.prompt(self.PROMPTS["credit_card"]["security_code"])
        print self.PROMPTS["credit_card"]["end_message"]
        return response

    def get_address(self, filetype):
        address = {}
        for label in ["first_name", "last_name", "address_line1", "address_line2",
                "city", "state", "zip_code", "country"]:
            address[label] = self.prompt(self.PROMPTS["address"][label])

        print "\nYou typed the following:\n"
        self.print_indent("    %s %s" % (address["first_name"], address["last_name"]))
        self.print_indent("    %s" % (address["address_line1"]))
        self.print_indent("    %s" % (address["address_line2"]))
        self.print_indent("    %s, %s %s" % (address["city"], address["state"], address["zip_code"]))
        self.print_indent("    %s" % (address["country"]))
        print ""

        if self.prompt_boolean(self.PROMPTS["address"]["confirmation_message"]):
            print self.PROMPTS[filetype]["end_message"]
            return address
        else:
            self.get_address(filetype)

    def build_prompt(self, base_prompt, description_list):
        prompt = base_prompt + "\n"
        prompt += "\n".join(description_list)
        return prompt

    def select_product_variants(self, variants_response):
        descriptions = []
        product_ids = []
        if (len(variants_response["variant_options"]) > 1):
            for i in xrange(len(variants_response["variant_options"])):
                current_descriptions_list = []
                current_option = variants_response["variant_options"][i]
                for dimension in current_option["dimensions"]:
                    current_descriptions_list.append(dimension["name"] + ": " + dimension["value"])
                if "unit_price" in current_option:
                    current_descriptions_list.append("Price: " + self.format_price(current_option["unit_price"]))
                product_ids.append(current_option["product_id"])
                descriptions.append(str(i) + ") " + ", ".join(current_descriptions_list))

            prompt = self.build_prompt(self.PROMPTS["select_product_variants"], descriptions)

            description_number = self.prompt(prompt,
                    ValidationHelpers.validate_number(len(descriptions)))
            chosen_product_id = product_ids[int(description_number)]
        else:
            chosen_product_id = variants_response["variant_options"][0]["product_id"]

        quantity = self.get_quantity()
        return [{
                "product_id": chosen_product_id,
                "quantity": quantity
                }]

    def format_price(self, price):
        price = str(price)
        if len(price) > 2:
            return "$" + price[:(-2)] + "." + price[(-2):]
        elif len(price) == 2:
            return "$0." + price
        elif len(price) == 1:
            return "$0.0" + price

    def get_quantity(self):
        quantity = self.prompt(self.PROMPTS["product_quantity"]).strip()
        if quantity == "":
            return 1
        else:
            return quantity

    def select_shipping_methods(self, shipping_response):
        descriptions = []
        shipping_ids = []
        for i in xrange(len(shipping_response["shipping_methods"])):
            current_method = shipping_response["shipping_methods"][i]
            descriptions.append(str(i) + ") " + current_method["name"] + \
                    ": " + current_method["description"])
            shipping_ids.append(current_method["shipping_method_id"])

        prompt = self.build_prompt(self.PROMPTS["select_shipping_methods"], descriptions)
        description_number = self.prompt(prompt,
                ValidationHelpers.validate_number(len(descriptions)))
        chosen_id = shipping_ids[int(description_number)]
        return chosen_id

if __name__ == '__main__':
    ZincWizard({'retailer': 'amazon',
        'client_token': 'public',
        #'shipping_address': "examples/shipping_address.json",
        #'billing_address': "examples/shipping_address.json",
        #'credit_card': "examples/credit_card.json"
        }).start()
<commit_msg>Fixing small errors/typos.<commit_after>from zinc_request_processor import ZincRequestProcessor
import sys
import json

WELCOME_BANNER = """
 ____      ____             __
|_  _|    |_  _|           [  |
  \ \  /\  / /.---.  .---.  | |  .--.   _ .--..--.  .---.
   \ \/  \/ // /__\\/ /'`\] | |/ .'`\ \[ `.-. .-. |/ /__\\
    \  /\  / | \__.,| \__.  | || \__. | | | | | | || \__.,
     \/  \/   '.__.''.___.'[___]'.__.' [___||__||__]'.__.'

                     _________
                    |  _   _  |
                    |_/ | | \_|.--.
                        | |  / .'`\ \
                       _| |_ | \__. |
                      |_____| '.__.'

            ________   _                   _
           |  __   _| (_)                 | |
           |_/  / /   __   _ .--.   .---. | |
              .'.' _ [  | [ `.-. | / /'`\]| |
            _/ /__/ | | |  | | | | | \__. |_|
           |________|[___][___||__]'.___.'(_)
"""

class ValidationHelpers(object):
    @classmethod
    def validate_number(klass, maximum, minimum=0):
        def validate(x):
            if (int(x) <= maximum and int(x) >= minimum):
                return True
            else:
                print "You must enter a number between %s and %s\n" % (minimum, maximum)
        return validate

    @classmethod
    def validate_boolean(klass):
        def validate(x):
            if (x == "y" or x == "n"):
                return True
            else:
                print "You must enter either 'y' or 'n'"
        return validate

    @classmethod
    def validate_credit_card(klass):
        def validate(card_number):
            digit_sum = 0
            num_digits = len(card_number)
            oddeven = num_digits & 1
            for count in range(0, num_digits):
                digit = int(card_number[count])
            if not (( count & 1 ) ^ oddeven ):
                digit = digit * 2
            if digit > 9:
                digit = digit - 9
            digit_sum += digit
            if ( (digit_sum % 10) == 0 ):
                return True
            else:
                print "Invalid credit card number"
        return validate

class ZincWizard(object):
    PROMPTS = {
        "product_variants": WELCOME_BANNER + "\nPlease please enter a product URL.",
        "product_quantity": "How many would you like to purchase? (Default: 1)",
        "select_product_variants": "This item comes in multiple variants. Please choose an option.",
        "select_shipping_methods": "This item has multiple shipping options. Please choose an option.",
        "security_code": "Please enter the CVV security code on your credit card.",
        "place_order": "Would you like to place this order? (y)/n",
        "gift": "Do you want this to be shipped as a gift? (y)/n",
        "shipping_address": {
            "start_message": "\nNow we'd like to get your shipping information.",
            "end_message": "\nYou've finished entering your shipping address!"
            },
        "address": {
            "first_name": "Please input your first name:",
            "last_name": "Please input your last name:",
            "address_line1": "Please input the first line of your shipping address:",
            "address_line2": "Please input the second line of your shipping address: (optional)",
            "city": "Please input your city:",
            "state": "Please input your state (e.g. CA, MA, etc.):",
            "zip_code": "Please input your zip code:",
            "country": "Please input your country (e.g. US):",
            "confirmation_message": "Is this your correct shipping address? (y)/n"
            },
        "billing_address" : {
            "start_message": "\nIs your billing address the same as your shipping address? (y)/n",
            "end_message": "\nYou've finished entering you billing address!"
            },
        "credit_card": {
            "start_message": "\nNow we'd like to get your credit card information.",
            "number": "Please input your credit card number",
            "expiration_month": "Please input your credit card expiration month (e.g. 03)",
            "expiration_year": "Please input your credit card expiration year (e.g. 2017)",
            "security_code": "Please input the CVV security code from your credit card",
            "end_message": "\nYou've finished entering your credit card information!"
            }
        }

    def __init__(self, options = None):
        self.options = (options if options is not None else {})
        self.response_data = {}
        self.security_code = None

    def start(self):
        self.get_product_variants(self.response_data)
        self.get_shipping_methods(self.response_data)
        self.get_store_card(self.response_data)
        self.get_review_order(self.response_data)
        self.get_place_order(self.response_data)

    def prompt(self, prompt, validation=None, max_attempts=3):
        attempts = 0
        while True:
            raw = raw_input(prompt + "\n")
            if (validation == None) or (validation != None and validation(raw)):
                return raw
            else:
                attempts += 1
                if attempts >= max_attempts:
                    print "You've reached the maximum number of attempts. Exiting!"
                    sys.exit()

    def prompt_boolean(self, prompt):
        result = self.prompt(prompt, ValidationHelpers.validate_boolean()).strip()
        if (result == "y" or result == ""):
            return True
        return False

    def get_product_variants(self, response_data):
        if "product_url" in self.options:
            product_url = self.options["product_url"]
        else:
            product_url = self.prompt(self.PROMPTS["product_variants"])

        print "\nProcessing request...\n"
        variants_response = ZincRequestProcessor.process("variant_options", {
                    "client_token": self.options["client_token"],
                    "retailer": self.options["retailer"],
                    "product_url": product_url
                    })
        response_data["variant_options_response"] = variants_response
        response_data["products"] = self.select_product_variants(variants_response)

    def get_shipping_methods(self, response_data):
        shipping_address = self.load_file_contents("shipping_address")
        print "\nProcessing request...\n"
        shipping_response = ZincRequestProcessor.process("shipping_methods", {
                    "client_token": self.options["client_token"],
                    "retailer": self.options["retailer"],
                    "products": response_data["products"],
                    "shipping_address": shipping_address
                })

        response_data["shipping_response"] = shipping_response
        response_data["shipping_address"] = shipping_address
        response_data["shipping_method_id"] = self.select_shipping_methods(shipping_response)

    def get_store_card(self, response_data):
        if "cc_token" in self.options and self.options["cc_token"] != None:
            response_data["cc_token"] = self.options["cc_token"]
        else:
            cc_data = self.load_file_contents("credit_card")
            billing_address = self.load_file_contents("billing_address")
            print "\nProcessing request...\n"
            store_card_response = ZincRequestProcessor.process("store_card", {
                        "client_token": self.options["client_token"],
                        "retailer": self.options["retailer"],
                        "billing_address": billing_address,
                        "number": cc_data["number"],
                        "expiration_month": cc_data["expiration_month"],
                        "expiration_year": cc_data["expiration_year"]
                    })

            response_data["store_card_response"] = store_card_response
            response_data["cc_token"] = store_card_response["cc_token"]

    def get_review_order(self, response_data):
        payment_method = {
                "cc_token": response_data["cc_token"],
                "security_code": self.get_security_code()
                }
        is_gift = self.get_is_gift()
        print "\nProcessing request...\n"
        review_order_response = ZincRequestProcessor.process("review_order", {
                    "client_token": self.options["client_token"],
                    "retailer": self.options["retailer"],
                    "products": response_data["products"],
                    "shipping_address": response_data["shipping_address"],
                    "is_gift": is_gift,
                    "shipping_method_id": response_data["shipping_method_id"],
                    "payment_method": payment_method,
                    "customer_email": "support@zinc.io"
                })

        response_data["review_order_response"] = review_order_response

    def get_place_order(self, response_data):
        self.print_price_components(response_data)
        if self.prompt_boolean(self.PROMPTS["place_order"]):
            print "\nProcessing request...\n"
            place_order_resonse = ZincRequestProcessor.process("place_order", {
                        "client_token": self.options["client_token"],
                        "place_order_key": response_data["review_order_response"]["place_order_key"]
                    })

            response_data["place_order_response"] = place_order_response
            print "HOORAY! You've successfully placed an order. Here are the details:\n"
            print "Amazon Order Id: %s" % place_order_response["merchant_order"]["merchant_order_id"]
            print "Total Price: %s" % place_order_response["price_components"]["total"]
            print place_order_response["shipping_method"]["name"] + ": " + place_order_response["shipping_method"]["description"]

    def print_price_components(self, response_data):
        components = response_data["review_order_response"]["price_components"]
        self.print_indent("Product Subtotal: %s" % self.format_price(components["subtotal"]))
        self.print_indent("Shipping Cost:    %s" % self.format_price(components["shipping"]))
        self.print_indent("Tax:              %s" % self.format_price(components["tax"]))
        if "gift_card" in components:
            self.print_indent("Gift Card:        %s" % self.format_price(components["gift_card"]))
        self.print_indent("Total:            %s" % self.format_price(components["total"]))

    def print_indent(self, value):
        print "    ", value

    def get_is_gift(self):
        if "gift" in self.options:
            return self.options["gift"]
        return self.prompt_boolean(self.PROMPTS["gift"])

    def get_security_code(self):
        if self.security_code != None:
            return self.security_code
        return self.prompt(self.PROMPTS["security_code"])

    def load_file_contents(self, filetype):
        if filetype in self.options and self.options[filetype] != None:
            with open(self.options[filetype], 'rb') as f:
                return json.loads(f.read())
        elif filetype == "shipping_address":
            print self.PROMPTS[filetype]["start_message"]
            return self.get_address(filetype)
        elif filetype == "billing_address":
            if self.prompt_boolean(self.PROMPTS[filetype]["start_message"]):
                return self.response_data["shipping_address"]
            else:
                return self.get_address(filetype)
        elif filetype == "credit_card":
            return self.get_credit_card_information()

    def get_credit_card_information(self):
        print self.PROMPTS["credit_card"]["start_message"]
        response = {}
        response["number"] = self.prompt(self.PROMPTS["credit_card"]["number"],
                ValidationHelpers.validate_credit_card())
        response["expiration_month"] = self.prompt(self.PROMPTS["credit_card"]["expiration_month"],
                ValidationHelpers.validate_number(12, 1))
        response["expiration_year"] = self.prompt(self.PROMPTS["credit_card"]["expiration_year"],
                ValidationHelpers.validate_number(2100, 2010))
        self.security_code = self.prompt(self.PROMPTS["credit_card"]["security_code"])
        print self.PROMPTS["credit_card"]["end_message"]
        return response

    def get_address(self, filetype):
        address = {}
        for label in ["first_name", "last_name", "address_line1", "address_line2",
                "city", "state", "zip_code", "country"]:
            address[label] = self.prompt(self.PROMPTS["address"][label])

        print "\nYou typed the following:\n"
        self.print_indent("    %s %s" % (address["first_name"], address["last_name"]))
        self.print_indent("    %s" % (address["address_line1"]))
        self.print_indent("    %s" % (address["address_line2"]))
        self.print_indent("    %s, %s %s" % (address["city"], address["state"], address["zip_code"]))
        self.print_indent("    %s" % (address["country"]))
        print ""

        if self.prompt_boolean(self.PROMPTS["address"]["confirmation_message"]):
            print self.PROMPTS[filetype]["end_message"]
            return address
        else:
            return self.get_address(filetype)

    def build_prompt(self, base_prompt, description_list):
        prompt = base_prompt + "\n"
        prompt += "\n".join(description_list)
        return prompt

    def select_product_variants(self, variants_response):
        descriptions = []
        product_ids = []
        if (len(variants_response["variant_options"]) > 1):
            for i in xrange(len(variants_response["variant_options"])):
                current_descriptions_list = []
                current_option = variants_response["variant_options"][i]
                for dimension in current_option["dimensions"]:
                    current_descriptions_list.append(dimension["name"] + ": " + dimension["value"])
                if "unit_price" in current_option:
                    current_descriptions_list.append("Price: " + self.format_price(current_option["unit_price"]))
                product_ids.append(current_option["product_id"])
                descriptions.append(str(i) + ") " + ", ".join(current_descriptions_list))

            prompt = self.build_prompt(self.PROMPTS["select_product_variants"], descriptions)

            description_number = self.prompt(prompt,
                    ValidationHelpers.validate_number(len(descriptions)-1))
            chosen_product_id = product_ids[int(description_number)]
        else:
            chosen_product_id = variants_response["variant_options"][0]["product_id"]

        quantity = self.get_quantity()
        return [{
                "product_id": chosen_product_id,
                "quantity": quantity
                }]

    def format_price(self, price):
        price = str(price)
        if len(price) > 2:
            return "$" + price[:(-2)] + "." + price[(-2):]
        elif len(price) == 2:
            return "$0." + price
        elif len(price) == 1:
            return "$0.0" + price

    def get_quantity(self):
        quantity = self.prompt(self.PROMPTS["product_quantity"]).strip()
        if quantity == "":
            return 1
        else:
            return quantity

    def select_shipping_methods(self, shipping_response):
        descriptions = []
        shipping_ids = []
        for i in xrange(len(shipping_response["shipping_methods"])):
            current_method = shipping_response["shipping_methods"][i]
            descriptions.append(str(i) + ") " + current_method["name"] + \
                    ": " + current_method["description"])
            shipping_ids.append(current_method["shipping_method_id"])

        prompt = self.build_prompt(self.PROMPTS["select_shipping_methods"], descriptions)
        description_number = self.prompt(prompt,
                ValidationHelpers.validate_number(len(descriptions)-1))
        chosen_id = shipping_ids[int(description_number)]
        return chosen_id

if __name__ == '__main__':
    ZincWizard({'retailer': 'amazon',
        'client_token': 'public',
        #'shipping_address': "examples/shipping_address.json",
        #'billing_address': "examples/shipping_address.json",
        #'credit_card': "examples/credit_card.json"
        }).start()
<|endoftext|>


<commit_before>import BaseHTTPServer
import httplib
import itertools
import logging
import os
import socket
import subprocess
import sys
import time
import traceback
import urlparse

from feather import connections, requests, servers
import greenhouse

__all__ = ["SizeBoundFile", "HTTPError", "HTTPRequest", "HTTPRequestHandler",
        "HTTPConnection"]

responses = BaseHTTPServer.BaseHTTPRequestHandler.responses

class HTTPRequest(object):
    '''a straightforward attribute holder that supports the following names:

    method
        GET, POST, PUT, HEAD, DELETE, etc.

    version
        the HTTP version as a tuple of integers. generally (1, 0) or (1, 1)

    scheme
        string of either "http" or "https"

    host
        the server host - tried to get first from Host: header, then from host
        in the path, then (if the path was relative) takes it from the server

    path
        the accessed path from the first line of the request

    querystring
        the full querystring from the path

    fragment
        the fragment portion of the url

    headers
        an object representing the HTTP headers. unless overridden,
        HTTPConnection provides an instance of httplib.HTTPMessage

    content
        a file-like object from which you can read[line[s]]() the body of the
        request
    '''
    __slots__ = [
            "request_line",
            "method",
            "version",
            "scheme",
            "host",
            "path",
            "querystring",
            "fragment",
            "headers",
            "content"]

    def __init__(self, **kwargs):
        for name in self.__slots__:
            setattr(self, name, kwargs.get(name, None))

class HTTPError(Exception):
    """raise this in an HTTPRequestHandler instance/subclass to bail out and
    send an error response
    """
    def __init__(self, code=500, body=None, headers=None):
        self.code = code
        self.body = body
        self.headers = headers or []

class SizeBoundFile(socket._fileobject):
    """a file object that doesn't attempt to read past a specified length.

    unless overridden, HTTPConnection uses this as request.content
    """
    def __init__(self, sock, length, mode='rb', bufsize=-1, close=False):
        self.length = length
        super(SizeBoundFile, self).__init__(sock, mode, bufsize, close)

    def read(self, size=-1):
        size = min(size, self.length)
        if size < 0: size = self.length
        data = super(SizeBoundFile, self).read(size)
        self.length -= min(self.length, len(data))
        return data

    def readlines(self):
        text = self.read()
        if text[-1] == "\n":
            text = text[:-1]
        return map(self._line_mapper, text.split("\n"))

    @staticmethod
    def _line_mapper(l):
        return l + '\n'

class HTTPRequestHandler(requests.RequestHandler):
    """the main application entry-point, this class handles a single request

    subclass this and provide do_METHOD methods for every HTTP method you wish
    to support (do_GET and do_POST is a good place to start).

    do_* methods should call methods provided by HTTPRequestHandler to supply
    the proper response:

    set_code(code)
        the integer HTTP response code (200 for successful)

    set_body(body)
        the argument may be either a string or an iterable of strings. in the
        latter case it is acceptable for it to be a generator or other lazy
        iterator to allow a long response to be generated and sent gradually
        without blocking the whole server process.

    add_header(name, value)
        add a single response header

    add_headers(headers)
        add a group of headers.  provide a list of two-tuples of (name, value)
        pairs
    """
    traceback_body = False

    def __init__(self, *args, **kwargs):
        super(HTTPRequestHandler, self).__init__(*args, **kwargs)
        self._headers = []
        self._code = self._body = None

    def set_code(self, code):
        self._code = code

    def set_body(self, body):
        self._body = body

    def add_header(self, name, value):
        self._headers.append((name, value))

    def add_headers(self, headers):
        self._headers.extend(headers)

    def handle(self, request):
        handler = getattr(self, "do_%s" % request.method, None)

        try:
            if not handler or handler(request) is NotImplemented:
                raise HTTPError(405) # Method Not Allowed

        except HTTPError, error:
            self.translate_http_error(error)

        except NotImplementedError:
            self.translate_http_error(HTTPError(405))

        return self.format_response()

    def handle_error(self, klass, exc, tb):
        if self.traceback_body:
            self.set_body(traceback.format_exception(klass, exc, tb))
        self.set_code(500)
        self.add_header('Content-type', 'text/plain')
        return self.format_response()

    def _have_header(self, header, required_value=None):
        header = header.lower()
        for name, value in self._headers:
            if name.lower() == header and \
                    (required_value is None or value == required_value):
                return True
        return False

    def translate_http_error(self, error):
        self.set_code(error.code)
        if not self._have_header('content-type'):
            self.add_header('Content-type', 'text/plain')
        self.add_headers(error.headers)
        self.set_body(error.body)

    def format_response(self):
        http_version = '.'.join(map(str, self.connection.http_version))
        code = self._code or 200
        status, long_status = responses[code]
        if self._body is None:
            self._body = long_status

        closed = self._have_header('connection', 'close')

        # any time the connection is about to be closed, send the header
        if self.connection.closing and not closed:
            self.add_header('Connection', 'close')
            closed = True

        # we MUST either send a Content-Length or close the connection
        if not self._have_header('content-length'):
            if isinstance(self._body, str):
                self.add_header('Content-Length', len(self._body))
            else:
                if not closed:
                    closed = True
                    self.add_header('Connection', 'close')
                self.connection.closing = True

        if not self.connection.keepalive_timeout and not closed:
            self.add_header('Connection', 'close')
            close = True

        headers = '\r\n'.join('%s: %s' % pair for pair in self._headers)

        head = 'HTTP/%s %d %s\r\n%s\r\n\r\n' % (
                http_version, code, status, headers)

        if isinstance(self._body, str):
            return (head + self._body,)

        # we don't want the headers to go in their own send() call, so prefix
        # them to the first item in the body iterable, then re-prefix that item
        iterator = iter(self._body)
        try:
            first_chunk = iterator.next()
        except StopIteration:
            first_chunk = ''
        return (itertools.chain([head + first_chunk], iterator),
            (code, len(head)))

    def do_GET(self, request):
        raise NotImplementedError()

    do_POST = do_PUT = do_HEAD = do_DELETE = do_GET

class HTTPConnection(connections.TCPConnection):
    """TCPConnection that speaks HTTP

    the main point of this class is to implement get_request so that it parses
    an HTTP request from the socket so the request_handler's handle() method
    receives an instance of HTTPRequest.

    there is not much overriding to be done at this level, but there are a few
    attributes that might be useful to change:

    request_handler
        this must be your HTTPRequestHandler subclass

    keepalive_timeout
        time in seconds before an inactive connection is closed. set to 0 to
        disable keepalive entirely

    http_version
        HTTP version number for responses as a tuple of ints. default is (1, 1)

    header_class
        callable that accepts a file-like object and returns a representation
        of the HTTP headers which will be used as request.headers. must not
        read more input than necessary. the default of httplib.HTTPMessage is a
        good one
    """
    request_handler = HTTPRequestHandler

    # header-parsing class from the stdlib
    header_class = httplib.HTTPMessage

    # we don't support changing the HTTP version inside a connection
    http_version = (1, 1)

    keepalive_timeout = 30

    def __init__(self, *args, **kwargs):
        super(HTTPConnection, self).__init__(*args, **kwargs)
        if self.keepalive_timeout:
            self.socket.settimeout(self.keepalive_timeout)

    def get_request(self):
        try:
            content = SizeBoundFile(self.socket, 0)
            request_line = content.readline()
            self.killable = False

            if request_line in ('\n', '\r\n'):
                request_line = content.readline()

            if not request_line:
                return None

            method, path, version_string = request_line.split(' ', 2)
            version_string = version_string.rstrip()

            if not method.isalpha() or method != method.upper():
                return None

            url = urlparse.urlsplit(path)

            if version_string[:5] != 'HTTP/':
                return None

            try:
                version = tuple(int(v) for v in version_string[5:].split("."))
            except ValueError:
                return None

            headers = self.header_class(content)

            if version < (1, 1):
                self.closing = True
            else:
                for name, val in headers.items():
                    if name.lower() == 'connection' and val.lower() == 'close':
                        self.closing = True
                        break

            scheme = url.scheme or "http"
            host = headers.get('host') or url.netloc or self.server_address

            if 'content-length' in headers:
                content.length = int(headers['content-length'])

            return HTTPRequest(
                    request_line=request_line,
                    method=method,
                    version=version,
                    scheme=scheme,
                    host=host,
                    path=url.path,
                    querystring=url.query,
                    fragment=url.fragment,
                    headers=headers,
                    content=content)

        except:
            return None

    @staticmethod
    def format_datetime(dt):
        month = {
            "01": "Jan",
            "02": "Feb",
            "03": "Mar",
            "04": "Apr",
            "05": "May",
            "06": "Jun",
            "07": "Jul",
            "08": "Aug",
            "09": "Sep",
            "10": "Oct",
            "11": "Nov",
            "12": "Dec",
            }[dt.strftime("%m")]
        tz = -time.altzone / 36
        neg = tz < 0
        tz = str(-tz).zfill(4)
        if neg:
            tz = "-%s" % tz
        return dt.strftime("%d/%%s/%Y:%H:%M:%S %%s") % (month, tz)

    def _get_browser_ip(self, request):
        if 'x-forwarded-for' in request.headers:
            return request.headers['x-forwarded-for'].strip()
        if 'x-real-ip' in request.headers:
            return request.headers['x-real-ip'].strip()
        return self.socket.getpeername()[0]

    def log_access(self, access_time, request, metadata, sent):
        code, head_len = metadata
        body_len = sent - head_len
        self.server._al_file.writelines([
            self.server.access_log_format % {
                'ip': self._get_browser_ip(request),
                'time': self.format_datetime(access_time),
                'request_line': request.request_line.rstrip(),
                'resp_code': code,
                'body_len': body_len,
                'referer': request.headers.get("http-referer", "-"),
                'user_agent': request.headers.get("user-agent", "-"),
            }])
        self.server._al_file.flush()

    def log_error(self, klass, exc, tb):
        self.server._el_file.write(
                "".join(traceback.format_exception(klass, exc, tb)))
        self.server._el_file.flush()

class HTTPServer(servers.TCPServer):
    """
    """
    connection_handler = HTTPConnection

    access_log_format = '%(ip)s - - [%(time)s] "%(request_line)s" ' + \
            '%(resp_code)d %(body_len)d "%(referer)s" "%(user_agent)s"\n'

    max_conns = subprocess.MAXFD - 6

    def __init__(self, *args, **kwargs):
        self.access_log = kwargs.pop("access_log", None)
        self.error_log = kwargs.pop("error_log", None)

        super(HTTPServer, self).__init__(*args, **kwargs)

    def _setup_loggers(self):
        if self.access_log:
            dirpath, fname = os.path.split(os.path.abspath(self.access_log))
            if not os.path.isdir(dirpath):
                os.mkdir(dirpath)
            self._al_file = greenhouse.File(self.access_log, 'a')
            self._close_al = True
        else:
            self._al_file = sys.stdout
            self._close_al = False

        if self.error_log:
            dirpath, fname = os.path.split(os.path.abspath(self.error_log))
            if not os.path.isdir(dirpath):
                os.mkdir(dirpath)
            self._el_file = greenhouse.File(self.error_log, 'a')
            self._close_el = True
        else:
            self._el_file = sys.stderr
            self._close_el = False

    def pre_fork_setup(self):
        super(HTTPServer, self).pre_fork_setup()
        self._setup_loggers()

    def cleanup(self):
        super(HTTPServer, self).cleanup()

        if self._close_al:
            self._al_file.close()

        if self._close_el:
            self._el_file.close()
<commit_msg>what was i thinking?<commit_after>import BaseHTTPServer
import httplib
import itertools
import logging
import os
import socket
import subprocess
import sys
import time
import traceback
import urlparse

from feather import connections, requests, servers
import greenhouse

__all__ = ["SizeBoundFile", "HTTPError", "HTTPRequest", "HTTPRequestHandler",
        "HTTPConnection"]

responses = BaseHTTPServer.BaseHTTPRequestHandler.responses

class HTTPRequest(object):
    '''a straightforward attribute holder that supports the following names:

    method
        GET, POST, PUT, HEAD, DELETE, etc.

    version
        the HTTP version as a tuple of integers. generally (1, 0) or (1, 1)

    scheme
        string of either "http" or "https"

    host
        the server host - tried to get first from Host: header, then from host
        in the path, then (if the path was relative) takes it from the server

    path
        the accessed path from the first line of the request

    querystring
        the full querystring from the path

    fragment
        the fragment portion of the url

    headers
        an object representing the HTTP headers. unless overridden,
        HTTPConnection provides an instance of httplib.HTTPMessage

    content
        a file-like object from which you can read[line[s]]() the body of the
        request
    '''
    __slots__ = [
            "request_line",
            "method",
            "version",
            "scheme",
            "host",
            "path",
            "querystring",
            "fragment",
            "headers",
            "content"]

    def __init__(self, **kwargs):
        for name in self.__slots__:
            setattr(self, name, kwargs.get(name, None))

class HTTPError(Exception):
    """raise this in an HTTPRequestHandler instance/subclass to bail out and
    send an error response
    """
    def __init__(self, code=500, body=None, headers=None):
        self.code = code
        self.body = body
        self.headers = headers or []

class SizeBoundFile(socket._fileobject):
    """a file object that doesn't attempt to read past a specified length.

    unless overridden, HTTPConnection uses this as request.content
    """
    def __init__(self, sock, length, mode='rb', bufsize=-1, close=False):
        self.length = length
        super(SizeBoundFile, self).__init__(sock, mode, bufsize, close)

    def read(self, size=-1):
        size = min(size, self.length)
        if size < 0: size = self.length
        data = super(SizeBoundFile, self).read(size)
        self.length -= min(self.length, len(data))
        return data

    def readlines(self):
        text = self.read()
        if text[-1] == "\n":
            text = text[:-1]
        return [l + '\n' for l in text.split("\n")]

class HTTPRequestHandler(requests.RequestHandler):
    """the main application entry-point, this class handles a single request

    subclass this and provide do_METHOD methods for every HTTP method you wish
    to support (do_GET and do_POST is a good place to start).

    do_* methods should call methods provided by HTTPRequestHandler to supply
    the proper response:

    set_code(code)
        the integer HTTP response code (200 for successful)

    set_body(body)
        the argument may be either a string or an iterable of strings. in the
        latter case it is acceptable for it to be a generator or other lazy
        iterator to allow a long response to be generated and sent gradually
        without blocking the whole server process.

    add_header(name, value)
        add a single response header

    add_headers(headers)
        add a group of headers.  provide a list of two-tuples of (name, value)
        pairs
    """
    traceback_body = False

    def __init__(self, *args, **kwargs):
        super(HTTPRequestHandler, self).__init__(*args, **kwargs)
        self._headers = []
        self._code = self._body = None

    def set_code(self, code):
        self._code = code

    def set_body(self, body):
        self._body = body

    def add_header(self, name, value):
        self._headers.append((name, value))

    def add_headers(self, headers):
        self._headers.extend(headers)

    def handle(self, request):
        handler = getattr(self, "do_%s" % request.method, None)

        try:
            if not handler or handler(request) is NotImplemented:
                raise HTTPError(405) # Method Not Allowed

        except HTTPError, error:
            self.translate_http_error(error)

        except NotImplementedError:
            self.translate_http_error(HTTPError(405))

        return self.format_response()

    def handle_error(self, klass, exc, tb):
        if self.traceback_body:
            self.set_body(traceback.format_exception(klass, exc, tb))
        self.set_code(500)
        self.add_header('Content-type', 'text/plain')
        return self.format_response()

    def _have_header(self, header, required_value=None):
        header = header.lower()
        for name, value in self._headers:
            if name.lower() == header and \
                    (required_value is None or value == required_value):
                return True
        return False

    def translate_http_error(self, error):
        self.set_code(error.code)
        if not self._have_header('content-type'):
            self.add_header('Content-type', 'text/plain')
        self.add_headers(error.headers)
        self.set_body(error.body)

    def format_response(self):
        http_version = '.'.join(map(str, self.connection.http_version))
        code = self._code or 200
        status, long_status = responses[code]
        if self._body is None:
            self._body = long_status

        closed = self._have_header('connection', 'close')

        # any time the connection is about to be closed, send the header
        if self.connection.closing and not closed:
            self.add_header('Connection', 'close')
            closed = True

        # we MUST either send a Content-Length or close the connection
        if not self._have_header('content-length'):
            if isinstance(self._body, str):
                self.add_header('Content-Length', len(self._body))
            else:
                if not closed:
                    closed = True
                    self.add_header('Connection', 'close')
                self.connection.closing = True

        if not self.connection.keepalive_timeout and not closed:
            self.add_header('Connection', 'close')
            close = True

        headers = '\r\n'.join('%s: %s' % pair for pair in self._headers)

        head = 'HTTP/%s %d %s\r\n%s\r\n\r\n' % (
                http_version, code, status, headers)

        if isinstance(self._body, str):
            return (head + self._body,)

        # we don't want the headers to go in their own send() call, so prefix
        # them to the first item in the body iterable, then re-prefix that item
        iterator = iter(self._body)
        try:
            first_chunk = iterator.next()
        except StopIteration:
            first_chunk = ''
        return (itertools.chain([head + first_chunk], iterator),
            (code, len(head)))

    def do_GET(self, request):
        raise NotImplementedError()

    do_POST = do_PUT = do_HEAD = do_DELETE = do_GET

class HTTPConnection(connections.TCPConnection):
    """TCPConnection that speaks HTTP

    the main point of this class is to implement get_request so that it parses
    an HTTP request from the socket so the request_handler's handle() method
    receives an instance of HTTPRequest.

    there is not much overriding to be done at this level, but there are a few
    attributes that might be useful to change:

    request_handler
        this must be your HTTPRequestHandler subclass

    keepalive_timeout
        time in seconds before an inactive connection is closed. set to 0 to
        disable keepalive entirely

    http_version
        HTTP version number for responses as a tuple of ints. default is (1, 1)

    header_class
        callable that accepts a file-like object and returns a representation
        of the HTTP headers which will be used as request.headers. must not
        read more input than necessary. the default of httplib.HTTPMessage is a
        good one
    """
    request_handler = HTTPRequestHandler

    # header-parsing class from the stdlib
    header_class = httplib.HTTPMessage

    # we don't support changing the HTTP version inside a connection
    http_version = (1, 1)

    keepalive_timeout = 30

    def __init__(self, *args, **kwargs):
        super(HTTPConnection, self).__init__(*args, **kwargs)
        if self.keepalive_timeout:
            self.socket.settimeout(self.keepalive_timeout)

    def get_request(self):
        try:
            content = SizeBoundFile(self.socket, 0)
            request_line = content.readline()
            self.killable = False

            if request_line in ('\n', '\r\n'):
                request_line = content.readline()

            if not request_line:
                return None

            method, path, version_string = request_line.split(' ', 2)
            version_string = version_string.rstrip()

            if not method.isalpha() or method != method.upper():
                return None

            url = urlparse.urlsplit(path)

            if version_string[:5] != 'HTTP/':
                return None

            try:
                version = tuple(int(v) for v in version_string[5:].split("."))
            except ValueError:
                return None

            headers = self.header_class(content)

            if version < (1, 1):
                self.closing = True
            else:
                for name, val in headers.items():
                    if name.lower() == 'connection' and val.lower() == 'close':
                        self.closing = True
                        break

            scheme = url.scheme or "http"
            host = headers.get('host') or url.netloc or self.server_address

            if 'content-length' in headers:
                content.length = int(headers['content-length'])

            return HTTPRequest(
                    request_line=request_line,
                    method=method,
                    version=version,
                    scheme=scheme,
                    host=host,
                    path=url.path,
                    querystring=url.query,
                    fragment=url.fragment,
                    headers=headers,
                    content=content)

        except:
            return None

    @staticmethod
    def format_datetime(dt):
        month = {
            "01": "Jan",
            "02": "Feb",
            "03": "Mar",
            "04": "Apr",
            "05": "May",
            "06": "Jun",
            "07": "Jul",
            "08": "Aug",
            "09": "Sep",
            "10": "Oct",
            "11": "Nov",
            "12": "Dec",
            }[dt.strftime("%m")]
        tz = -time.altzone / 36
        neg = tz < 0
        tz = str(-tz).zfill(4)
        if neg:
            tz = "-%s" % tz
        return dt.strftime("%d/%%s/%Y:%H:%M:%S %%s") % (month, tz)

    def _get_browser_ip(self, request):
        if 'x-forwarded-for' in request.headers:
            return request.headers['x-forwarded-for'].strip()
        if 'x-real-ip' in request.headers:
            return request.headers['x-real-ip'].strip()
        return self.socket.getpeername()[0]

    def log_access(self, access_time, request, metadata, sent):
        code, head_len = metadata
        body_len = sent - head_len
        self.server._al_file.writelines([
            self.server.access_log_format % {
                'ip': self._get_browser_ip(request),
                'time': self.format_datetime(access_time),
                'request_line': request.request_line.rstrip(),
                'resp_code': code,
                'body_len': body_len,
                'referer': request.headers.get("http-referer", "-"),
                'user_agent': request.headers.get("user-agent", "-"),
            }])
        self.server._al_file.flush()

    def log_error(self, klass, exc, tb):
        self.server._el_file.write(
                "".join(traceback.format_exception(klass, exc, tb)))
        self.server._el_file.flush()

class HTTPServer(servers.TCPServer):
    """
    """
    connection_handler = HTTPConnection

    access_log_format = '%(ip)s - - [%(time)s] "%(request_line)s" ' + \
            '%(resp_code)d %(body_len)d "%(referer)s" "%(user_agent)s"\n'

    max_conns = subprocess.MAXFD - 6

    def __init__(self, *args, **kwargs):
        self.access_log = kwargs.pop("access_log", None)
        self.error_log = kwargs.pop("error_log", None)

        super(HTTPServer, self).__init__(*args, **kwargs)

    def _setup_loggers(self):
        if self.access_log:
            dirpath, fname = os.path.split(os.path.abspath(self.access_log))
            if not os.path.isdir(dirpath):
                os.mkdir(dirpath)
            self._al_file = greenhouse.File(self.access_log, 'a')
            self._close_al = True
        else:
            self._al_file = sys.stdout
            self._close_al = False

        if self.error_log:
            dirpath, fname = os.path.split(os.path.abspath(self.error_log))
            if not os.path.isdir(dirpath):
                os.mkdir(dirpath)
            self._el_file = greenhouse.File(self.error_log, 'a')
            self._close_el = True
        else:
            self._el_file = sys.stderr
            self._close_el = False

    def pre_fork_setup(self):
        super(HTTPServer, self).pre_fork_setup()
        self._setup_loggers()

    def cleanup(self):
        super(HTTPServer, self).cleanup()

        if self._close_al:
            self._al_file.close()

        if self._close_el:
            self._el_file.close()
<|endoftext|>


<commit_before># coding: utf-8

from cffi import FFI

from .error import *

ffi = FFI()

errnos =  ['EADDRINUSE', 'EADDRNOTAVAIL', 'EAGAIN', 'ECONNREFUSED', 'EFAULT',
           'EFSM', 'EINPROGRESS', 'EINVAL', 'EMTHREAD', 'ENETDOWN', 'ENOBUFS',
           'ENOCOMPATPROTO', 'ENODEV', 'ENOMEM', 'ENOTSUP', 'EPROTONOSUPPORT',
           'ETERM', 'ENOTSOCK', 'EMSGSIZE', 'EAFNOSUPPORT', 'ENETUNREACH',
           'ECONNABORTED', 'ECONNRESET', 'ENOTCONN', 'ETIMEDOUT',
           'EHOSTUNREACH', 'ENETRESET']

zmq2_cons = ['ZMQ_MSG_MORE' , 'ZMQ_MSG_SHARED', 'ZMQ_MSG_MASK',
             'ZMQ_UPSTREAM', 'ZMQ_DOWNSTREAM', 'ZMQ_MCAST_LOOP',
             'ZMQ_RECOVERY_IVL_MSEC', 'ZMQ_NOBLOCK', 'ZMQ_HWM',
             'ZMQ_SWAP']

socket_cons = ['ZMQ_PAIR', 'ZMQ_PUB', 'ZMQ_SUB', 'ZMQ_REQ', 'ZMQ_REP',
               'ZMQ_DEALER', 'ZMQ_ROUTER', 'ZMQ_PULL', 'ZMQ_PUSH', 'ZMQ_XPUB',
               'ZMQ_XSUB', 'ZMQ_XREQ', 'ZMQ_XREP']

zmq_base_cons = ['ZMQ_VERSION', 'ZMQ_AFFINITY', 'ZMQ_IDENTITY', 'ZMQ_SUBSCRIBE',
                 'ZMQ_UNSUBSCRIBE', 'ZMQ_RATE', 'ZMQ_RECOVERY_IVL',
                 'ZMQ_SNDBUF', 'ZMQ_RCVBUF', 'ZMQ_RCVMORE', 'ZMQ_FD',
                 'ZMQ_EVENTS', 'ZMQ_TYPE', 'ZMQ_LINGER', 'ZMQ_RECONNECT_IVL',
                 'ZMQ_BACKLOG', 'ZMQ_RECONNECT_IVL_MAX', 'ZMQ_RCVTIMEO',
                 'ZMQ_SNDTIMEO', 'ZMQ_SNDMORE', 'ZMQ_POLLIN', 'ZMQ_POLLOUT',
                 'ZMQ_POLLERR', 'ZMQ_STREAMER', 'ZMQ_FORWARDER', 'ZMQ_QUEUE']

zmq3_cons = ['ZMQ_DONTWAIT', 'ZMQ_MORE', 'ZMQ_MAXMSGSIZE', 'ZMQ_SNDHWM',
             'ZMQ_RCVHWM', 'ZMQ_MULTICAST_HOPS', 'ZMQ_IPV4ONLY',
             'ZMQ_LAST_ENDPOINT', 'ZMQ_ROUTER_BEHAVIOR', 'ZMQ_TCP_KEEPALIVE',
             'ZMQ_TCP_KEEPALIVE_CNT', 'ZMQ_TCP_KEEPALIVE_IDLE',
             'ZMQ_TCP_KEEPALIVE_INTVL', 'ZMQ_TCP_ACCEPT_FILTER',
             'ZMQ_EVENT_CONNECTED', 'ZMQ_EVENT_CONNECT_DELAYED',
             'ZMQ_EVENT_CONNECT_RETRIED', 'ZMQ_EVENT_LISTENING',
             'ZMQ_EVENT_BIND_FAILED', 'ZMQ_EVENT_ACCEPTED',
             'ZMQ_EVENT_ACCEPT_FAILED', 'ZMQ_EVENT_CLOSED',
             'ZMQ_EVENT_CLOSE_FAILED']

core_functions = \
'''
void* zmq_init(int);
int zmq_term(void *context);

void* zmq_socket(void *context, int type);
int zmq_close(void *socket);

int zmq_bind(void *socket, const char *endpoint);
int zmq_connect(void *socket, const char *endpoint);

int zmq_errno(void);
'''

core32_functions = \
'''
int zmq_unbind(void *socket, const char *endpoint);
int zmq_disconnect(void *socket, const char *endpoint);
'''

message_functions = \
'''
typedef struct {
    void *content;
    unsigned char flags;
    unsigned char vsm_size;
    unsigned char vsm_data [30];
} zmq_msg_t;

typedef ... zmq_free_fn;

int zmq_msg_init(zmq_msg_t *msg);
int zmq_msg_init_size(zmq_msg_t *msg, size_t size);
int zmq_msg_init_data(zmq_msg_t *msg,
                      void *data,
                      size_t size,
                      zmq_free_fn *ffn,
                      void *hint);

size_t zmq_msg_size(zmq_msg_t *msg);
void *zmq_msg_data(zmq_msg_t *msg);
int zmq_msg_close(zmq_msg_t *msg);

int zmq_send(void *socket, zmq_msg_t *msg, int flags);
int zmq_recv(void *socket, zmq_msg_t *msg, int flags);
'''

message32_functions = \
'''
typedef struct {unsigned char _ [32];} zmq_msg_t;
typedef ... zmq_free_fn;

int zmq_msg_init(zmq_msg_t *msg);
int zmq_msg_init_size(zmq_msg_t *msg, size_t size);
int zmq_msg_init_data(zmq_msg_t *msg,
                      void *data,
                      size_t size,
                      zmq_free_fn *ffn,
                      void *hint);

size_t zmq_msg_size(zmq_msg_t *msg);
void *zmq_msg_data(zmq_msg_t *msg);
int zmq_msg_close(zmq_msg_t *msg);

int zmq_sendmsg(void *socket, zmq_msg_t *msg, int flags);
int zmq_recvmsg(void *socket, zmq_msg_t *msg, int flags);
'''

sockopt_functions = \
'''
int zmq_getsockopt(void *socket,
                   int option_name,
                   void *option_value,
                   size_t *option_len);

int zmq_setsockopt(void *socket,
                   int option_name,
                   const void *option_value,
                   size_t option_len);
'''

polling_functions = \
'''
typedef struct
{
    void *socket;
    int fd;
    short events;
    short revents;
} zmq_pollitem_t;

int zmq_poll(zmq_pollitem_t *items, int nitems, long timeout);
'''

extra_functions = \
'''
void* memcpy(void *restrict s1, const void *restrict s2, size_t n);
'''

def get_version():
    ffi_check = FFI()
    ffi_check.cdef('void zmq_version(int *major, int *minor, int *patch);')
    C_check_version = ffi_check.verify('#include <zmq.h>',
                                        libraries=['c', 'zmq'])
    major = ffi.new('int*')
    minor = ffi.new('int*')
    patch = ffi.new('int*')

    C_check_version.zmq_version(major, minor, patch)

    return (int(major[0]), int(minor[0]), int(patch[0]))

constant_names = []

zmq_version = get_version()[0]

if zmq_version == 2:
    constant_names = errnos + socket_cons + zmq_base_cons + zmq2_cons
else:
    constant_names = errnos + socket_cons + zmq_base_cons + zmq3_cons

def _make_defines(names):
    _names = []
    for name in names:
        define_line = "#define %s ..." % (name)
        _names.append(define_line)

    return "\n".join(_names)

constants = _make_defines(constant_names)

if zmq_version == 2:
    functions = ''.join([constants,
                         core_functions,
                         core22_functions,
                         message_functions,
                         sockopt_functions,
                         polling_functions,
                         extra_functions])
elif zmq_version == 3:
    functions = ''.join([constants,
                         core_functions,
                         core32_functions,
                         message32_functions,
                         sockopt_functions,
                         polling_functions,
                         extra_functions])
else:
    raise Exception("Bad ZMQ Install")

ffi.cdef(functions)

C = ffi.verify('''
    #include <stddef.h>
    #include <string.h>
    #include <zmq.h>
''', libraries=['c', 'zmq'])

nsp = new_sizet_pointer = lambda length: ffi.new('size_t*', length)

new_uint64_pointer = lambda: (ffi.new('uint64_t*'),
                              nsp(ffi.sizeof('uint64_t')))
new_int64_pointer = lambda: (ffi.new('int64_t*'),
                             nsp(ffi.sizeof('int64_t')))
new_int_pointer = lambda: (ffi.new('int*'),
                           nsp(ffi.sizeof('int')))
new_binary_data = lambda length: (ffi.new('char[%d]' % (length)),
                                  nsp(ffi.sizeof('char') * length))

value_uint64_pointer = lambda val : (ffi.new('uint64_t*', val),
                                     ffi.sizeof('uint64_t'))
value_int64_pointer = lambda val: (ffi.new('int64_t*', val),
                                   ffi.sizeof('int64_t'))
value_int_pointer = lambda val: (ffi.new('int*', val),
                                 ffi.sizeof('int'))
value_binary_data = lambda val, length: (ffi.new('char[%d]' % (length), val),
                                         ffi.sizeof('char') * length)
<commit_msg>fix missing zmq2.2 function<commit_after># coding: utf-8

from cffi import FFI

from .error import *

ffi = FFI()

errnos =  ['EADDRINUSE', 'EADDRNOTAVAIL', 'EAGAIN', 'ECONNREFUSED', 'EFAULT',
           'EFSM', 'EINPROGRESS', 'EINVAL', 'EMTHREAD', 'ENETDOWN', 'ENOBUFS',
           'ENOCOMPATPROTO', 'ENODEV', 'ENOMEM', 'ENOTSUP', 'EPROTONOSUPPORT',
           'ETERM', 'ENOTSOCK', 'EMSGSIZE', 'EAFNOSUPPORT', 'ENETUNREACH',
           'ECONNABORTED', 'ECONNRESET', 'ENOTCONN', 'ETIMEDOUT',
           'EHOSTUNREACH', 'ENETRESET']

zmq2_cons = ['ZMQ_MSG_MORE' , 'ZMQ_MSG_SHARED', 'ZMQ_MSG_MASK',
             'ZMQ_UPSTREAM', 'ZMQ_DOWNSTREAM', 'ZMQ_MCAST_LOOP',
             'ZMQ_RECOVERY_IVL_MSEC', 'ZMQ_NOBLOCK', 'ZMQ_HWM',
             'ZMQ_SWAP']

socket_cons = ['ZMQ_PAIR', 'ZMQ_PUB', 'ZMQ_SUB', 'ZMQ_REQ', 'ZMQ_REP',
               'ZMQ_DEALER', 'ZMQ_ROUTER', 'ZMQ_PULL', 'ZMQ_PUSH', 'ZMQ_XPUB',
               'ZMQ_XSUB', 'ZMQ_XREQ', 'ZMQ_XREP']

zmq_base_cons = ['ZMQ_VERSION', 'ZMQ_AFFINITY', 'ZMQ_IDENTITY', 'ZMQ_SUBSCRIBE',
                 'ZMQ_UNSUBSCRIBE', 'ZMQ_RATE', 'ZMQ_RECOVERY_IVL',
                 'ZMQ_SNDBUF', 'ZMQ_RCVBUF', 'ZMQ_RCVMORE', 'ZMQ_FD',
                 'ZMQ_EVENTS', 'ZMQ_TYPE', 'ZMQ_LINGER', 'ZMQ_RECONNECT_IVL',
                 'ZMQ_BACKLOG', 'ZMQ_RECONNECT_IVL_MAX', 'ZMQ_RCVTIMEO',
                 'ZMQ_SNDTIMEO', 'ZMQ_SNDMORE', 'ZMQ_POLLIN', 'ZMQ_POLLOUT',
                 'ZMQ_POLLERR', 'ZMQ_STREAMER', 'ZMQ_FORWARDER', 'ZMQ_QUEUE']

zmq3_cons = ['ZMQ_DONTWAIT', 'ZMQ_MORE', 'ZMQ_MAXMSGSIZE', 'ZMQ_SNDHWM',
             'ZMQ_RCVHWM', 'ZMQ_MULTICAST_HOPS', 'ZMQ_IPV4ONLY',
             'ZMQ_LAST_ENDPOINT', 'ZMQ_ROUTER_BEHAVIOR', 'ZMQ_TCP_KEEPALIVE',
             'ZMQ_TCP_KEEPALIVE_CNT', 'ZMQ_TCP_KEEPALIVE_IDLE',
             'ZMQ_TCP_KEEPALIVE_INTVL', 'ZMQ_TCP_ACCEPT_FILTER',
             'ZMQ_EVENT_CONNECTED', 'ZMQ_EVENT_CONNECT_DELAYED',
             'ZMQ_EVENT_CONNECT_RETRIED', 'ZMQ_EVENT_LISTENING',
             'ZMQ_EVENT_BIND_FAILED', 'ZMQ_EVENT_ACCEPTED',
             'ZMQ_EVENT_ACCEPT_FAILED', 'ZMQ_EVENT_CLOSED',
             'ZMQ_EVENT_CLOSE_FAILED']

core_functions = \
'''
void* zmq_init(int);
int zmq_term(void *context);

void* zmq_socket(void *context, int type);
int zmq_close(void *socket);

int zmq_bind(void *socket, const char *endpoint);
int zmq_connect(void *socket, const char *endpoint);

int zmq_errno(void);
'''

core22_functions = \
'''
int zmq_device(int device, const void *frontend, const void *backend);
'''

core32_functions = \
'''
int zmq_unbind(void *socket, const char *endpoint);
int zmq_disconnect(void *socket, const char *endpoint);
'''

message_functions = \
'''
typedef struct {
    void *content;
    unsigned char flags;
    unsigned char vsm_size;
    unsigned char vsm_data [30];
} zmq_msg_t;

typedef ... zmq_free_fn;

int zmq_msg_init(zmq_msg_t *msg);
int zmq_msg_init_size(zmq_msg_t *msg, size_t size);
int zmq_msg_init_data(zmq_msg_t *msg,
                      void *data,
                      size_t size,
                      zmq_free_fn *ffn,
                      void *hint);

size_t zmq_msg_size(zmq_msg_t *msg);
void *zmq_msg_data(zmq_msg_t *msg);
int zmq_msg_close(zmq_msg_t *msg);

int zmq_send(void *socket, zmq_msg_t *msg, int flags);
int zmq_recv(void *socket, zmq_msg_t *msg, int flags);
'''

message32_functions = \
'''
typedef struct {unsigned char _ [32];} zmq_msg_t;
typedef ... zmq_free_fn;

int zmq_msg_init(zmq_msg_t *msg);
int zmq_msg_init_size(zmq_msg_t *msg, size_t size);
int zmq_msg_init_data(zmq_msg_t *msg,
                      void *data,
                      size_t size,
                      zmq_free_fn *ffn,
                      void *hint);

size_t zmq_msg_size(zmq_msg_t *msg);
void *zmq_msg_data(zmq_msg_t *msg);
int zmq_msg_close(zmq_msg_t *msg);

int zmq_sendmsg(void *socket, zmq_msg_t *msg, int flags);
int zmq_recvmsg(void *socket, zmq_msg_t *msg, int flags);
'''

sockopt_functions = \
'''
int zmq_getsockopt(void *socket,
                   int option_name,
                   void *option_value,
                   size_t *option_len);

int zmq_setsockopt(void *socket,
                   int option_name,
                   const void *option_value,
                   size_t option_len);
'''

polling_functions = \
'''
typedef struct
{
    void *socket;
    int fd;
    short events;
    short revents;
} zmq_pollitem_t;

int zmq_poll(zmq_pollitem_t *items, int nitems, long timeout);
'''

extra_functions = \
'''
void* memcpy(void *restrict s1, const void *restrict s2, size_t n);
'''

def get_version():
    ffi_check = FFI()
    ffi_check.cdef('void zmq_version(int *major, int *minor, int *patch);')
    C_check_version = ffi_check.verify('#include <zmq.h>',
                                        libraries=['c', 'zmq'])
    major = ffi.new('int*')
    minor = ffi.new('int*')
    patch = ffi.new('int*')

    C_check_version.zmq_version(major, minor, patch)

    return (int(major[0]), int(minor[0]), int(patch[0]))

constant_names = []

zmq_version = get_version()[0]

if zmq_version == 2:
    constant_names = errnos + socket_cons + zmq_base_cons + zmq2_cons
else:
    constant_names = errnos + socket_cons + zmq_base_cons + zmq3_cons

def _make_defines(names):
    _names = []
    for name in names:
        define_line = "#define %s ..." % (name)
        _names.append(define_line)

    return "\n".join(_names)

constants = _make_defines(constant_names)

if zmq_version == 2:
    functions = ''.join([constants,
                         core_functions,
                         core22_functions,
                         message_functions,
                         sockopt_functions,
                         polling_functions,
                         extra_functions])
elif zmq_version == 3:
    functions = ''.join([constants,
                         core_functions,
                         core32_functions,
                         message32_functions,
                         sockopt_functions,
                         polling_functions,
                         extra_functions])
else:
    raise Exception("Bad ZMQ Install")

ffi.cdef(functions)

C = ffi.verify('''
    #include <stddef.h>
    #include <string.h>
    #include <zmq.h>
''', libraries=['c', 'zmq'])

nsp = new_sizet_pointer = lambda length: ffi.new('size_t*', length)

new_uint64_pointer = lambda: (ffi.new('uint64_t*'),
                              nsp(ffi.sizeof('uint64_t')))
new_int64_pointer = lambda: (ffi.new('int64_t*'),
                             nsp(ffi.sizeof('int64_t')))
new_int_pointer = lambda: (ffi.new('int*'),
                           nsp(ffi.sizeof('int')))
new_binary_data = lambda length: (ffi.new('char[%d]' % (length)),
                                  nsp(ffi.sizeof('char') * length))

value_uint64_pointer = lambda val : (ffi.new('uint64_t*', val),
                                     ffi.sizeof('uint64_t'))
value_int64_pointer = lambda val: (ffi.new('int64_t*', val),
                                   ffi.sizeof('int64_t'))
value_int_pointer = lambda val: (ffi.new('int*', val),
                                 ffi.sizeof('int'))
value_binary_data = lambda val, length: (ffi.new('char[%d]' % (length), val),
                                         ffi.sizeof('char') * length)
<|endoftext|>


<commit_before>#!/usr/bin/env python

import math
import random
import sys

import pygame
from pygame.locals import *
from noise import pnoise1, pnoise2, snoise2

BEIGE  = (200, 200, 100)
BLACK  = (  0,   0,   0)
BLUE   = (  0,   0, 200)
GREEN  = (  0, 255,   0)
RED    = (255,   0,   0)
WHITE  = (255, 255, 255)
CYAN = (  0, 255, 255)

def setup_screen(screen_size=(900, 900)):
    surf = pygame.display.set_mode(screen_size, RESIZABLE)
    pygame.display.set_caption('Pyland Gen 1.0')
    return surf

class IslandGenerator():
    """ Generates a random graph of noise. (Not really an Island) """
    def __init__(self):
        """ Initialize some pnoise generator defaults. """
        self.span = 8.0
        self.octaves = 8
        self.scale = 40

    def gen_border(self):
        """
        Generate a border to apply to our island to build shoreline.

        Returns a list of (x, y) points of generated pnoise.
        """
        points = 360
        base = random.randint(0, 500)
        border = []
        for i in range(points):
            x = float(i) * self.span / points
            y = pnoise1(x + base, self.octaves) * 1
            y += pnoise1(x + base, self.octaves + 4) * 2
            y *= self.scale
            border.append((i, y))
        return border

def scale_to_polar(border, radius=200):
    """ Apply our border to our island. """
    radii = (radius + y for _, y in border)  # Adjust radii
    angles = (x * math.pi / 180.0 for x, _ in border)  # Convert to radians
    return zip(radii, angles)

def polar_to_rectangular(polar_coords):
    return [(r * math.cos(theta) + 450, r * math.sin(theta) + 450) \
            for r, theta in polar_coords]  # To rectangular coords

def render_island(surf, coords, radius):
    """ Renders an aaline of a series of points. """
    pygame.draw.circle(surf, RED, (450, 450), radius, 1)  # Original centre
    pygame.draw.aalines(surf, BEIGE, True, coords, False)  # Island shore
    for point in coords:  # Data points
        pygame.draw.circle(surf, GREEN, (int(point[0]), int(point[1])), 1)

def render_border(surf, points):
    """ Renders an aaline of a series of points. """
    point_list = [(x + 50, -y + 800) for x, y in points]  # Up is -ve
    pygame.draw.line(surf, CYAN, (50, 800), (410, 800), 1)  # x-axis
    pygame.draw.line(surf, CYAN, (50, 800), (50, 700), 1)  # y-axis

    pygame.draw.lines(surf, WHITE, False, point_list, 1)
    for x, y in point_list:  # points
        pygame.draw.circle(surf, RED, (int(x), int(y)), 1)

def flood_fill(surf):
    screen_size = surf.get_size()
    center_x, center_y = screen_size[0]/2, screen_size[1]/2
    start_color = surf.get_at((center_x, center_y))
    seen = []
    WHITE = (255, 255, 255, 255)
    for dx, dy in [(1, 0), (-1, 0), (0, 1), (0, -1)]:
        x, y = center_x + dx, center_y + dy
        surf.set_at((x, y), WHITE)
        if surf.get_at((x, y)) == start_color:
            pass

def get_input():
    """ Wait for input. """
    for event in pygame.event.get():
        if event.type == QUIT:
            return 'quit', None
        elif event.type == KEYDOWN:
            shift = bool(pygame.key.get_mods() & pygame.KMOD_LSHIFT)
            if event.key == (K_s):
                return 'span', shift
            elif event.key == (K_o):
                return 'octaves', shift
            elif event.key == (K_c):
                return 'scale', shift
            elif event.key in (K_q, K_ESCAPE):
                return 'quit', None
            elif event.key == K_SPACE:
                return 'regen', None

def main():
    print('Pyland Gen 1.0')
    pygame.init()
    clock = pygame.time.Clock()
    surface = setup_screen()

    generator = IslandGenerator()
    radius = 200
    result = 'regen'
    while True:
        clock.tick(10)

        if result == 'quit':
            pygame.quit()
            sys.exit()
        elif result == 'span':
            sign = +1 if shifted else -1
            generator.span += sign * 1
            result = 'regen'
        elif result == 'scale':
            sign = +1 if shifted else -1
            generator.scale += sign * 10
            result = 'regen'
        elif result == 'octaves':
            sign = +1 if shifted else -1
            generator.octaves += sign * 1
            result = 'regen'
        if result == 'regen':
            surface.fill(BLACK)
            border = generator.gen_border()  # Generate random noise
            render_border(surface, border)  # Draw it

            polar_coords = scale_to_polar(border, radius=radius)  # Wrap it around a circle
            rect_coords = polar_to_rectangular(polar_coords)  # Conver to (x, y)
            render_island(surface, rect_coords, radius)  # Graph island

            flood_fill(surface)  # Fill Island w/ color
            pygame.display.flip()

        result = get_input()
        if result and len(result) > 1:
            result, shifted = result

if __name__ == '__main__':
    main()

<commit_msg>Start working on Flood Fill again<commit_after>#!/usr/bin/env python

import math
import random
import sys

import pygame
from pygame.locals import *
from noise import pnoise1, pnoise2, snoise2

BEIGE  = (200, 200, 100)
BLACK  = (  0,   0,   0)
BLUE   = (  0,   0, 200)
GREEN  = (  0, 255,   0)
RED    = (255,   0,   0)
WHITE  = (255, 255, 255)
CYAN = (  0, 255, 255)

def setup_screen(screen_size=(900, 900)):
    surf = pygame.display.set_mode(screen_size, RESIZABLE)
    pygame.display.set_caption('Pyland Gen 1.0')
    return surf

class IslandGenerator():
    """ Generates a random graph of noise. (Not really an Island) """
    def __init__(self):
        """ Initialize some pnoise generator defaults. """
        self.span = 8.0
        self.octaves = 8
        self.scale = 40

    def gen_border(self):
        """
        Generate a border to apply to our island to build shoreline.

        Returns a list of (x, y) points of generated pnoise.
        """
        points = 360
        base = random.randint(0, 500)
        border = []
        for i in range(points):
            x = float(i) * self.span / points
            y = pnoise1(x + base, self.octaves) * 1
            y += pnoise1(x + base, self.octaves + 4) * 2
            y *= self.scale
            border.append((i, y))
        return border

def scale_to_polar(border, radius=200):
    """ Apply our border to our island. """
    radii = (radius + y for _, y in border)  # Adjust radii
    angles = (x * math.pi / 180.0 for x, _ in border)  # Convert to radians
    return zip(radii, angles)

def polar_to_rectangular(polar_coords):
    return [(r * math.cos(theta) + 450, r * math.sin(theta) + 450) \
            for r, theta in polar_coords]  # To rectangular coords

def render_island(surf, coords, radius):
    """ Renders an aaline of a series of points. """
    pygame.draw.circle(surf, RED, (450, 450), radius, 1)  # Original centre
    pygame.draw.aalines(surf, BEIGE, True, coords, False)  # Island shore
    for point in coords:  # Data points
        pygame.draw.circle(surf, GREEN, (int(point[0]), int(point[1])), 1)

def render_border(surf, points):
    """ Renders an aaline of a series of points. """
    point_list = [(x + 50, -y + 800) for x, y in points]  # Up is -ve
    pygame.draw.line(surf, CYAN, (50, 800), (410, 800), 1)  # x-axis
    pygame.draw.line(surf, CYAN, (50, 800), (50, 700), 1)  # y-axis

    pygame.draw.lines(surf, WHITE, False, point_list, 1)
    for x, y in point_list:  # points
        pygame.draw.circle(surf, RED, (int(x), int(y)), 1)

def flood_fill(surf):
    print('Flood filling')
    screen_size = surf.get_size()
    center_x, center_y = screen_size[0]/2, screen_size[1]/2
    print(center_x, center_y)
    start_color = surf.get_at((center_x, center_y))  # Black
    seen = set()
    neighbours = set()
    WHITE = (255, 255, 255, 255)
    for dx, dy in [(0, 0), (1, 0), (-1, 0), (0, 1), (0, -1)]:  # Check 4 neighbours
        x, y = center_x + dx, center_y + dy
        if surf.get_at((x, y)) == start_color:
            surf.set_at((x, y), WHITE)  # Set color to white
            seen.add((x, y))

def get_input():
    """ Wait for input. """
    for event in pygame.event.get():
        if event.type == QUIT:
            return 'quit', None
        elif event.type == KEYDOWN:
            shift = bool(pygame.key.get_mods() & pygame.KMOD_LSHIFT)
            if event.key == (K_s):
                return 'span', shift
            elif event.key == (K_o):
                return 'octaves', shift
            elif event.key == (K_c):
                return 'scale', shift
            elif event.key in (K_q, K_ESCAPE):
                return 'quit', None
            elif event.key == K_SPACE:
                return 'regen', None

def main():
    print('Pyland Gen 1.0')
    pygame.init()
    clock = pygame.time.Clock()
    surface = setup_screen()

    generator = IslandGenerator()
    radius = 200
    result = 'regen'
    while True:
        clock.tick(10)

        if result == 'quit':
            pygame.quit()
            sys.exit()
        elif result == 'span':
            sign = +1 if shifted else -1
            generator.span += sign * 1
            result = 'regen'
        elif result == 'scale':
            sign = +1 if shifted else -1
            generator.scale += sign * 10
            result = 'regen'
        elif result == 'octaves':
            sign = +1 if shifted else -1
            generator.octaves += sign * 1
            result = 'regen'
        if result == 'regen':
            surface.fill(BLACK)
            border = generator.gen_border()  # Generate random noise
            render_border(surface, border)  # Draw it

            polar_coords = scale_to_polar(border, radius=radius)  # Wrap it around a circle
            rect_coords = polar_to_rectangular(polar_coords)  # Conver to (x, y)
            render_island(surface, rect_coords, radius)  # Graph island

            flood_fill(surface)  # Fill Island w/ color
            pygame.display.flip()

        result = get_input()
        if result and len(result) > 1:
            result, shifted = result

if __name__ == '__main__':
    main()

<|endoftext|>


<commit_before>import time
import sys
import os
import csv

from ztag.errors import IgnoreObject

import redis

from kafka import KafkaProducer

class Stream(object):

    def __init__(self, incoming, outgoing, transforms=None, logger=None):
        super(Stream, self).__init__()
        self.incoming = incoming
        self.outgoing = outgoing
        self.transforms = transforms or list()
        self.logger = logger

    def run(self):
        skipped = 0
        handled = 0
        for obj in self.incoming:
            if obj is None:
                continue
            try:
                out = obj
                for transformer in self.transforms:
                    out = transformer.transform(out)
                self.outgoing.take(out)
                handled += 1
            except IgnoreObject as e:
                if self.logger:
                    self.logger.debug(e.original_exception)
                    self.logger.trace(obj)
                continue
        self.outgoing.cleanup()
        return (handled, skipped)

class Incoming(object):
    pass

class InputFile(Incoming):

    def __init__(self, input_file=sys.stdin):
        self.input_file = input_file

    def __iter__(self):
        for line in self.input_file:
            yield line

class InputCSV(Incoming):

    def __init__(self, input_file=sys.stdin):
        self.input_file = input_file
        self.csvdict = csv.DictReader(self.input_file)

    def __iter__(self):
        for record in self.csvdict:
            yield record

class Outgoing(object):

    def __init__(self, *args, **kwargs):
        pass

    def take(self, obj):
        raise NotImplementedError

    def cleanup(self):
        pass

class PythonPrint(Outgoing):

    def __init__(self, *args, **kwargs):
        super(PythonPrint, self).__init__()

    def take(self, obj):
        print obj

class OutputFile(Outgoing):

    def __init__(self, output_file=sys.stdout, *args, **kwargs):
        super(OutputFile, self).__init__()
        self.output_file = output_file

    def take(self, obj):
        self.output_file.write(obj)
        self.output_file.write("\n")

class RedisQueue(Outgoing):

    CERTIFICATES_QUEUE = "certificate"
    PUBKEY_QUEUE = "pubkey"
    # we might as well try to do a whole bunch. The _worst_ case scenario
    # by setting a limit too high is that the server runs out of memory
    # and kills python and the task fails. Which would have happened
    # anyway, because we couldn't connect to redis.
    MAX_RETRIES = 60
    BATCH_SIZE = 250

    def __init__(self, logger=None, destination=None, *args, **kwargs):
        super(RedisQueue, self).__init__(*args, **kwargs)
        host = os.environ.get('ZTAG_REDIS_HOST', 'localhost')
        port = int(os.environ.get('ZTAG_REDIS_PORT', 6379))
        if destination == "full_ipv4":
            queue = "ipv4"
        elif destination == "alexa_top1mil":
            queue = "domain"
        else:
            raise Exception("invalid destination: %s" % destination)
        self.logger = logger
        self.queue = queue
        try:
            self.redis = redis.Redis(host=host, port=port, db=0,
                                     socket_connect_timeout=10)
        except redis.ConnectionError as e:
            msg = "could not connect to redis: %s" % str(e)
            self.logger.fatal(msg)
        # batching
        self.queued = 0
        self.retries = 0
        self.records = []
        self.certificates = []

    def push(self, noretry=False):
        if self.queued == 0:
            return
        try:
            p = self.redis.pipeline()
            for r in self.records:
                p.rpush(self.queue, r)
            for r in self.certificates:
                p.rpush(self.CERTIFICATES_QUEUE, r)
            p.execute()
            self.queued = 0
            self.records = []
            self.certificates = []
            self.retries = 0
        except redis.ConnectionError as e:
            time.sleep(1.0)
            self.retries += 1
            if self.retries > self.MAX_RETRIES or noretry:
                msg = "redis connection error: %s" % str(e)
                self.logger.fatal(msg)
                self.redis = None

    def take(self, pbout):
        self.records.append(pbout.transformed)
        self.certificates.extend(pbout.certificates)
        self.queued += (len(pbout.certificates) + 1)
        if self.queued > self.BATCH_SIZE:
            self.push()

    def cleanup(self):
        return self.push(noretry=True)

class Kafka(Outgoing):

    def __init__(self, logger=None, destination=None, *args, **kwargs):
        if destination == "full_ipv4":
            self.topic = "ipv4"
        elif destination == "alexa_top1mil":
            self.topic = "domain"
        else:
            raise Exception("invalid destination: %s" % destination)
        host = os.environ.get('KAFKA_BOOTSTRAP_HOST', 'localhost:9092')
        self.main_producer = KafkaProducer(bootstrap_servers=host,
                                    compression_type="lz4")
        self.cert_producer = KafkaProducer(bootstrap_servers=host,
                                    compression_type="lz4")

    def take(self, pbout):
        for certificate in pbout.certificates:
            self.cert_producer.send("certificate", certificate)
        self.main_producer.send(self.topic, pbout.transformed)

    def cleanup(self):
        if self.main_producer:
            self.main_producer.flush()
        if self.cert_producer:
            self.cert_producer.flush()

<commit_msg>Better fix<commit_after>import time
import sys
import os
import csv

from ztag.errors import IgnoreObject

import redis

from kafka import KafkaProducer

class Stream(object):

    def __init__(self, incoming, outgoing, transforms=None, logger=None):
        super(Stream, self).__init__()
        self.incoming = incoming
        self.outgoing = outgoing
        self.transforms = transforms or list()
        self.logger = logger

    def run(self):
        skipped = 0
        handled = 0
        for obj in self.incoming:
            try:
                out = obj
                for transformer in self.transforms:
                    out = transformer.transform(out)
                    if out is None:
                        raise IgnoreObject()
                self.outgoing.take(out)
                handled += 1
            except IgnoreObject as e:
                if self.logger:
                    self.logger.debug(e.original_exception)
                    self.logger.trace(obj)
                continue
        self.outgoing.cleanup()
        return (handled, skipped)

class Incoming(object):
    pass

class InputFile(Incoming):

    def __init__(self, input_file=sys.stdin):
        self.input_file = input_file

    def __iter__(self):
        for line in self.input_file:
            yield line

class InputCSV(Incoming):

    def __init__(self, input_file=sys.stdin):
        self.input_file = input_file
        self.csvdict = csv.DictReader(self.input_file)

    def __iter__(self):
        for record in self.csvdict:
            yield record

class Outgoing(object):

    def __init__(self, *args, **kwargs):
        pass

    def take(self, obj):
        raise NotImplementedError

    def cleanup(self):
        pass

class PythonPrint(Outgoing):

    def __init__(self, *args, **kwargs):
        super(PythonPrint, self).__init__()

    def take(self, obj):
        print obj

class OutputFile(Outgoing):

    def __init__(self, output_file=sys.stdout, *args, **kwargs):
        super(OutputFile, self).__init__()
        self.output_file = output_file

    def take(self, obj):
        self.output_file.write(obj)
        self.output_file.write("\n")

class RedisQueue(Outgoing):

    CERTIFICATES_QUEUE = "certificate"
    PUBKEY_QUEUE = "pubkey"
    # we might as well try to do a whole bunch. The _worst_ case scenario
    # by setting a limit too high is that the server runs out of memory
    # and kills python and the task fails. Which would have happened
    # anyway, because we couldn't connect to redis.
    MAX_RETRIES = 60
    BATCH_SIZE = 250

    def __init__(self, logger=None, destination=None, *args, **kwargs):
        super(RedisQueue, self).__init__(*args, **kwargs)
        host = os.environ.get('ZTAG_REDIS_HOST', 'localhost')
        port = int(os.environ.get('ZTAG_REDIS_PORT', 6379))
        if destination == "full_ipv4":
            queue = "ipv4"
        elif destination == "alexa_top1mil":
            queue = "domain"
        else:
            raise Exception("invalid destination: %s" % destination)
        self.logger = logger
        self.queue = queue
        try:
            self.redis = redis.Redis(host=host, port=port, db=0,
                                     socket_connect_timeout=10)
        except redis.ConnectionError as e:
            msg = "could not connect to redis: %s" % str(e)
            self.logger.fatal(msg)
        # batching
        self.queued = 0
        self.retries = 0
        self.records = []
        self.certificates = []

    def push(self, noretry=False):
        if self.queued == 0:
            return
        try:
            p = self.redis.pipeline()
            for r in self.records:
                p.rpush(self.queue, r)
            for r in self.certificates:
                p.rpush(self.CERTIFICATES_QUEUE, r)
            p.execute()
            self.queued = 0
            self.records = []
            self.certificates = []
            self.retries = 0
        except redis.ConnectionError as e:
            time.sleep(1.0)
            self.retries += 1
            if self.retries > self.MAX_RETRIES or noretry:
                msg = "redis connection error: %s" % str(e)
                self.logger.fatal(msg)
                self.redis = None

    def take(self, pbout):
        self.records.append(pbout.transformed)
        self.certificates.extend(pbout.certificates)
        self.queued += (len(pbout.certificates) + 1)
        if self.queued > self.BATCH_SIZE:
            self.push()

    def cleanup(self):
        return self.push(noretry=True)

class Kafka(Outgoing):

    def __init__(self, logger=None, destination=None, *args, **kwargs):
        if destination == "full_ipv4":
            self.topic = "ipv4"
        elif destination == "alexa_top1mil":
            self.topic = "domain"
        else:
            raise Exception("invalid destination: %s" % destination)
        host = os.environ.get('KAFKA_BOOTSTRAP_HOST', 'localhost:9092')
        self.main_producer = KafkaProducer(bootstrap_servers=host,
                                    compression_type="lz4")
        self.cert_producer = KafkaProducer(bootstrap_servers=host,
                                    compression_type="lz4")

    def take(self, pbout):
        for certificate in pbout.certificates:
            self.cert_producer.send("certificate", certificate)
        self.main_producer.send(self.topic, pbout.transformed)

    def cleanup(self):
        if self.main_producer:
            self.main_producer.flush()
        if self.cert_producer:
            self.cert_producer.flush()

<|endoftext|>