<commit_before>import csv

from dateutil.relativedelta import relativedelta

from django.conf import settings
from django.db import models
from django.db.models.signals import post_save
from django.utils import timezone
from django.utils.translation import ugettext as _
from django.dispatch import receiver

from django_extensions.db.fields import ModificationDateTimeField, CreationDateTimeField

from apps.projects.models import Project, ProjectPhases
from apps.sepa.sepa import SepaDocument, SepaAccount

from .fields import MoneyField
from .utils import money_from_cents
from .choices import PayoutLineStatuses, PayoutRules

class Payout(models.Model):
    """
    A projects is payed after it's fully funded in the first batch (2x/month).
    Project payouts are checked manually. Selected projects can be exported to a SEPA file.
    """

    planned = models.DateField(_("Planned"), help_text=_("Date that this batch should be processed."))

    project = models.ForeignKey('projects.Project')

    payout_rule = models.CharField(
        _("Payout rule"), max_length=20,
        choices=PayoutRules.choices,
        help_text=_("The payout rule for this project.")
    )

    status = models.CharField(
        _("status"), max_length=20, choices=PayoutLineStatuses.choices)
    created = CreationDateTimeField(_("Created"))
    updated = ModificationDateTimeField(_("Updated"))

    amount_raised = MoneyField(
        _("amount raised"), help_text=_('Amount raised when Payout was created.')
    )

    sender_account_number = models.CharField(max_length=100)
    receiver_account_number = models.CharField(max_length=100, blank=True)
    receiver_account_iban = models.CharField(max_length=100, blank=True)
    receiver_account_bic = models.CharField(max_length=100, blank=True)
    receiver_account_name = models.CharField(max_length=100)
    receiver_account_city = models.CharField(max_length=100)
    receiver_account_country = models.CharField(max_length=100, null=True)

    invoice_reference = models.CharField(max_length=100)
    description_line1 = models.CharField(max_length=100, blank=True, default="")
    description_line2 = models.CharField(max_length=100, blank=True, default="")
    description_line3 = models.CharField(max_length=100, blank=True, default="")
    description_line4 = models.CharField(max_length=100, blank=True, default="")

    @property
    def amount_payout(self):
        return '%.2f' % (float(self.amount) / 100)

    @property
    def current_amount_safe(self):
        return '%.2f' % (self.project.projectcampaign.money_safe * settings.PROJECT_PAYOUT_RATE / 100)

    @property
    def is_valid(self):
        # TODO: Do a more advanced check. Maybe use IBAN check by a B. Q. Konrath?
        if self.receiver_account_iban and self.receiver_account_bic:
            return True
        return False

    @property
    def amount_safe(self):
        return int(round(self.project.projectcampaign.money_safe * settings.PROJECT_PAYOUT_RATE))

    def __unicode__(self):
        date = self.created.strftime('%d-%m-%Y')
        return  self.invoice_reference + " : " + date + " : " + self.receiver_account_number + " : EUR " + str(self.amount_payout)

class BankMutationLine(models.Model):

    created = CreationDateTimeField(_("Created"))
    bank_mutation = models.ForeignKey("payouts.BankMutation")

    issuer_account_number = models.CharField(max_length=100)
    currency = models.CharField(max_length=3)
    start_date = models.DateField(_("Date started"))
    dc = models.CharField(_("Debet/Credit"), max_length=1)
    amount = models.DecimalField(decimal_places=2, max_digits=15)
    account_number = models.CharField(max_length=100)
    account_name = models.CharField(max_length=100)
    transaction_type = models.CharField(max_length=10)

    invoice_reference = models.CharField(max_length=100)

    description_line1 = models.CharField(max_length=100, blank=True, default="")
    description_line2 = models.CharField(max_length=100, blank=True, default="")
    description_line3 = models.CharField(max_length=100, blank=True, default="")
    description_line4 = models.CharField(max_length=100, blank=True, default="")

    payout = models.ForeignKey("payouts.Payout", null=True)

    def __unicode__(self):
        return str(self.start_date) + " " + self.dc + " : " + self.account_name + " [" + self.account_number + "]  " + \
            " EUR " + str(self.amount)

class BankMutation(models.Model):

    created = CreationDateTimeField(_("Created"))
    mut_file = models.FileField(_("Uploaded mutation file"), upload_to="bank_mutations", null=True)
    mutations = models.TextField(blank=True)

    def save(self, force_insert=False, force_update=False, using=None):
        super(BankMutation, self).save()
        self.mutations = self.mut_file.read()
        self.parse_file()
        self.mut_file = None

    def parse_file(self):
        mutations = csv.reader(self.mut_file)
        for m in mutations:
            if len(m) > 1:
                date = m[2]
                date = date[0:4] + "-" + date[4:6] + "-" + date[6:]
                line = BankMutationLine(issuer_account_number=m[0], currency=m[1], start_date=date, dc=m[3],
                                        amount=m[4], account_number=m[5], account_name=m[6], transaction_type=m[8],
                                        invoice_reference=m[10], description_line1=m[11], description_line2=m[12],
                                        description_line3=m[13], description_line4=m[14],
                                        bank_mutation=self)
                line.save()
        match_debit_mutations()

    def __unicode__(self):
        return "Bank Mutations " + str(self.created.strftime('%B %Y'))

@receiver(post_save, weak=False, sender=Project)
def create_payout_for_fully_funded_project(sender, instance, created, **kwargs):

    project = instance
    now = timezone.now()

    # Check projects in phase Act that have asked for money.
    # import ipdb; ipdb.set_trace()
    if project.phase == ProjectPhases.act and project.projectcampaign.money_asked:
        if now.day <= 15:
            next_date = timezone.datetime(now.year, now.month, 15)
        else:
            next_date = timezone.datetime(now.year, now.month, 1) + relativedelta(months=1)

        if project.projectcampaign.money_donated >= project.projectcampaign.money_asked:
            # Fully funded, set payout rule to 5
            payout_rule = PayoutRules.five
        else:
            payout_rule = PayoutRules.twelve

        amount_raised = money_from_cents(
            project.projectcampaign.money_donated
        )
        try:
            # Update existing Payout
            payout = Payout.objects.get(project=project)

            if payout.status == PayoutLineStatuses.new:
                # Update planned payout date and payout rule for new Payouts
                payout.planned = next_date
                payout.payout_rule = payout_rule
                payout.save()

        except Payout.DoesNotExist:

            # Create new Payout
            payout = Payout.objects.create(
                planned=next_date,
                project=project,
                status=PayoutLineStatuses.new,
                amount_raised=amount_raised,
                payout_rule=payout_rule
            )

            organization = project.projectplan.organization
            payout.receiver_account_bic = organization.account_bic
            payout.receiver_account_iban = organization.account_iban
            payout.receiver_account_number = organization.account_number
            payout.receiver_account_name = organization.account_name
            payout.receiver_account_city = organization.account_city
            payout.receiver_account_country = organization.account_bank_country
            payout.invoice_reference = 'PP'
            payout.save()
            payout.invoice_reference = str(project.id) + '-' + str(payout.id)
            payout.save()

def create_sepa_xml(payouts):
    batch_id = timezone.datetime.strftime(timezone.now(), '%Y%m%d%H%I%S')
    sepa = SepaDocument(type='CT')
    debtor = SepaAccount(name=settings.SEPA['name'], iban=settings.SEPA['iban'], bic=settings.SEPA['bic'])
    sepa.set_debtor(debtor)
    sepa.set_info(message_identification=batch_id, payment_info_id=batch_id)
    sepa.set_initiating_party(name=settings.SEPA['name'], id=settings.SEPA['id'])

    for line in payouts.all():
        creditor = SepaAccount(name=line.receiver_account_name, iban=line.receiver_account_iban,
                               bic=line.receiver_account_bic)
        sepa.add_credit_transfer(creditor=creditor, amount=line.amount, creditor_payment_id=line.invoice_reference)
    return sepa.as_xml()

def match_debit_mutations():
    lines = BankMutationLine.objects.filter(dc='D', payout__isnull=True).all()
    for line in lines:

        date = line.start_date

        try:
            payout = Payout.objects.filter(invoice_reference=line.invoice_reference).get()
            line.matched = True
            line.payout_line = payout
            line.save()
            payout.status = Payout.PayoutLineStatuses.completed
            payout.save()

            payout.project.payout_date = date
            payout.project.save()

        except Payout.DoesNotExist:
            pass

<commit_msg>Do not update payout rule automatically.<commit_after>import csv

from dateutil.relativedelta import relativedelta

from django.conf import settings
from django.db import models
from django.db.models.signals import post_save
from django.utils import timezone
from django.utils.translation import ugettext as _
from django.dispatch import receiver

from django_extensions.db.fields import ModificationDateTimeField, CreationDateTimeField

from apps.projects.models import Project, ProjectPhases
from apps.sepa.sepa import SepaDocument, SepaAccount

from .fields import MoneyField
from .utils import money_from_cents
from .choices import PayoutLineStatuses, PayoutRules

class Payout(models.Model):
    """
    A projects is payed after it's fully funded in the first batch (2x/month).
    Project payouts are checked manually. Selected projects can be exported to a SEPA file.
    """

    planned = models.DateField(_("Planned"), help_text=_("Date that this batch should be processed."))

    project = models.ForeignKey('projects.Project')

    payout_rule = models.CharField(
        _("Payout rule"), max_length=20,
        choices=PayoutRules.choices,
        help_text=_("The payout rule for this project.")
    )

    status = models.CharField(
        _("status"), max_length=20, choices=PayoutLineStatuses.choices)
    created = CreationDateTimeField(_("Created"))
    updated = ModificationDateTimeField(_("Updated"))

    amount_raised = MoneyField(
        _("amount raised"), help_text=_('Amount raised when Payout was created.')
    )

    sender_account_number = models.CharField(max_length=100)
    receiver_account_number = models.CharField(max_length=100, blank=True)
    receiver_account_iban = models.CharField(max_length=100, blank=True)
    receiver_account_bic = models.CharField(max_length=100, blank=True)
    receiver_account_name = models.CharField(max_length=100)
    receiver_account_city = models.CharField(max_length=100)
    receiver_account_country = models.CharField(max_length=100, null=True)

    invoice_reference = models.CharField(max_length=100)
    description_line1 = models.CharField(max_length=100, blank=True, default="")
    description_line2 = models.CharField(max_length=100, blank=True, default="")
    description_line3 = models.CharField(max_length=100, blank=True, default="")
    description_line4 = models.CharField(max_length=100, blank=True, default="")

    @property
    def amount_payout(self):
        return '%.2f' % (float(self.amount) / 100)

    @property
    def current_amount_safe(self):
        return '%.2f' % (self.project.projectcampaign.money_safe * settings.PROJECT_PAYOUT_RATE / 100)

    @property
    def is_valid(self):
        # TODO: Do a more advanced check. Maybe use IBAN check by a B. Q. Konrath?
        if self.receiver_account_iban and self.receiver_account_bic:
            return True
        return False

    @property
    def amount_safe(self):
        return int(round(self.project.projectcampaign.money_safe * settings.PROJECT_PAYOUT_RATE))

    def __unicode__(self):
        date = self.created.strftime('%d-%m-%Y')
        return  self.invoice_reference + " : " + date + " : " + self.receiver_account_number + " : EUR " + str(self.amount_payout)

class BankMutationLine(models.Model):

    created = CreationDateTimeField(_("Created"))
    bank_mutation = models.ForeignKey("payouts.BankMutation")

    issuer_account_number = models.CharField(max_length=100)
    currency = models.CharField(max_length=3)
    start_date = models.DateField(_("Date started"))
    dc = models.CharField(_("Debet/Credit"), max_length=1)
    amount = models.DecimalField(decimal_places=2, max_digits=15)
    account_number = models.CharField(max_length=100)
    account_name = models.CharField(max_length=100)
    transaction_type = models.CharField(max_length=10)

    invoice_reference = models.CharField(max_length=100)

    description_line1 = models.CharField(max_length=100, blank=True, default="")
    description_line2 = models.CharField(max_length=100, blank=True, default="")
    description_line3 = models.CharField(max_length=100, blank=True, default="")
    description_line4 = models.CharField(max_length=100, blank=True, default="")

    payout = models.ForeignKey("payouts.Payout", null=True)

    def __unicode__(self):
        return str(self.start_date) + " " + self.dc + " : " + self.account_name + " [" + self.account_number + "]  " + \
            " EUR " + str(self.amount)

class BankMutation(models.Model):

    created = CreationDateTimeField(_("Created"))
    mut_file = models.FileField(_("Uploaded mutation file"), upload_to="bank_mutations", null=True)
    mutations = models.TextField(blank=True)

    def save(self, force_insert=False, force_update=False, using=None):
        super(BankMutation, self).save()
        self.mutations = self.mut_file.read()
        self.parse_file()
        self.mut_file = None

    def parse_file(self):
        mutations = csv.reader(self.mut_file)
        for m in mutations:
            if len(m) > 1:
                date = m[2]
                date = date[0:4] + "-" + date[4:6] + "-" + date[6:]
                line = BankMutationLine(issuer_account_number=m[0], currency=m[1], start_date=date, dc=m[3],
                                        amount=m[4], account_number=m[5], account_name=m[6], transaction_type=m[8],
                                        invoice_reference=m[10], description_line1=m[11], description_line2=m[12],
                                        description_line3=m[13], description_line4=m[14],
                                        bank_mutation=self)
                line.save()
        match_debit_mutations()

    def __unicode__(self):
        return "Bank Mutations " + str(self.created.strftime('%B %Y'))

@receiver(post_save, weak=False, sender=Project)
def create_payout_for_fully_funded_project(sender, instance, created, **kwargs):

    project = instance
    now = timezone.now()

    # Check projects in phase Act that have asked for money.
    # import ipdb; ipdb.set_trace()
    if project.phase == ProjectPhases.act and project.projectcampaign.money_asked:
        if now.day <= 15:
            next_date = timezone.datetime(now.year, now.month, 15)
        else:
            next_date = timezone.datetime(now.year, now.month, 1) + relativedelta(months=1)

        if project.projectcampaign.money_donated >= project.projectcampaign.money_asked:
            # Fully funded, set payout rule to 5
            payout_rule = PayoutRules.five
        else:
            payout_rule = PayoutRules.twelve

        amount_raised = money_from_cents(
            project.projectcampaign.money_donated
        )
        try:
            # Update existing Payout
            payout = Payout.objects.get(project=project)

            if payout.status == PayoutLineStatuses.new:
                # Update planned payout date for new Payouts
                payout.planned = next_date
                payout.save()

        except Payout.DoesNotExist:

            # Create new Payout
            payout = Payout.objects.create(
                planned=next_date,
                project=project,
                status=PayoutLineStatuses.new,
                amount_raised=amount_raised,
                payout_rule=payout_rule
            )

            organization = project.projectplan.organization
            payout.receiver_account_bic = organization.account_bic
            payout.receiver_account_iban = organization.account_iban
            payout.receiver_account_number = organization.account_number
            payout.receiver_account_name = organization.account_name
            payout.receiver_account_city = organization.account_city
            payout.receiver_account_country = organization.account_bank_country
            payout.invoice_reference = 'PP'
            payout.save()
            payout.invoice_reference = str(project.id) + '-' + str(payout.id)
            payout.save()

def create_sepa_xml(payouts):
    batch_id = timezone.datetime.strftime(timezone.now(), '%Y%m%d%H%I%S')
    sepa = SepaDocument(type='CT')
    debtor = SepaAccount(name=settings.SEPA['name'], iban=settings.SEPA['iban'], bic=settings.SEPA['bic'])
    sepa.set_debtor(debtor)
    sepa.set_info(message_identification=batch_id, payment_info_id=batch_id)
    sepa.set_initiating_party(name=settings.SEPA['name'], id=settings.SEPA['id'])

    for line in payouts.all():
        creditor = SepaAccount(name=line.receiver_account_name, iban=line.receiver_account_iban,
                               bic=line.receiver_account_bic)
        sepa.add_credit_transfer(creditor=creditor, amount=line.amount, creditor_payment_id=line.invoice_reference)
    return sepa.as_xml()

def match_debit_mutations():
    lines = BankMutationLine.objects.filter(dc='D', payout__isnull=True).all()
    for line in lines:

        date = line.start_date

        try:
            payout = Payout.objects.filter(invoice_reference=line.invoice_reference).get()
            line.matched = True
            line.payout_line = payout
            line.save()
            payout.status = Payout.PayoutLineStatuses.completed
            payout.save()

            payout.project.payout_date = date
            payout.project.save()

        except Payout.DoesNotExist:
            pass

<|endoftext|>


<commit_before>import discord
from discord.ext import commands
from .utils import checks
from __main__ import send_cmd_help
from cogs.utils.dataIO import dataIO, fileIO

import json
import os
import asyncio
import subprocess

#def out(command):
#"""This function runs a shell script and collects the terminal response"""
#	result = run(command, stdout=PIPE, stderr=PIPE, universal_newlines=True, shell=True)
#	return result.stdout

class arkserver:
	"""Ark Server commands"""

	def __init__(self, bot):
		self.bot = bot
		self.settings = dataIO.load_json("data/arkserver/settings.json")

	async def out(self, command, channel):
		p = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
		for line in p.stdout.readlines():
			await self.bot.send_message(channel,"{0}".format(line))
		revtal = p.wait()

	@commands.group(pass_context=True)
	@checks.mod_or_permissions(manage_webhooks=True)
	async def ark(self, ctx):
		"""Commands related to Ark Server Management"""
		if ctx.invoked_subcommand is None:
			await self.bot.send_cmd_help(ctx)

	@ark.command(pass_context=True)
	async def checkupdate(self):
		"""Checks for ark updates - does not actually start the update"""
		channel = ctx.message.channel
		output = self.out("arkmanager checkupdate", channel)

	@ark.command(pass_context=True, name="stop")
	@checks.is_owner()
	async def ark_stop(self):
		"""Stops the Ark Server"""
		channel = ctx.message.channel
		output = self.out("arkmanager stop", channel)

	@ark.command(pass_context=True, name="toggle")
	@checks.is_owner()
	async def ark_toggle(self):
		"""Toggles autoupdating"""
		if self.settings["AutoUpdate"] == True:
			self.settings["AutoUpdate"] = False
			await self.bot.say("Automatic updating is now disabled.")
		else:
			self.settings["AutoUpdate"] = True
			await self.bot.say("Automatic server updating is now enabled.")
		dataIO.save_json('data/arkserver/settings.json', self.settings)

	@ark.command(pass_context=True, name="start")
	@checks.is_owner()
	async def ark_start(self):
		"""Starts the Ark Server"""
		channel = ctx.message.channel
		output = self.out("arkmanager start", channel)

	@ark.command(pass_context=True, name="status")
	async def ark_status(self, ctx):
		"""Checks the server status"""
		channel = ctx.message.channel
		output = await self.out("arkmanager status", channel)

	@ark.command(pass_context=True, name="restart")
	async def ark_restart(self, ctx):
		"""Restarts the ARK Server with a 60 second delay"""
		CurrentUpdating = self.settings["AutoUpdate"]
		channel = ctx.message.channel
		delay = 60
		self.settings["AutoUpdate"] = False #this makes sure autoupdate does not activate while the server is already busy
		await self.bot.say("Restarting in {0} seconds...".format(delay))
		text = "This server will restart in " + str(delay) + " seconds for maintenance."
		output = self.out('arkmanager broadcast' + ' ' + '"' + text + '"', channel)
		await asyncio.sleep(delay)
		output = out("arkmanager restart", channel)
		self.settings["AutoUpdate"] = CurrentUpdating #sets Updating back to the state it was before the command was run

	@ark.command(pass_context=True, name="update")
	async def ark_update(self, ctx, delay : int = 60):
		"""Stops the ARK Server, installs updates, then reboots"""
		CurrentUpdating = self.settings["AutoUpdate"]
		self.settings["AutoUpdate"] = False #this makes sure autoupdate does not activate while the server is already busy
		if delay > 600:
			delay = 600
		await self.bot.say("Restarting in {0} seconds...".format(delay))
		text = "This server will restart in " + str(delay) + " seconds for updates."
		output = self.out('arkmanager broadcast' + ' ' + '"' + text + '"')
		await asyncio.sleep(delay)
		output = self.out("arkmanager update --update-mods --backup")
		await self.bot.say("{0}".format(output))
		self.settings["AutoUpdate"] = CurrentUpdating #sets Updating back to the state it was before the command was run

	@ark.command(pass_context=True, name="save")
	async def ark_save(self):
		"""Saves the world state"""
		channel = ctx.message.channel
		output = self.out("arkmanager saveworld", channel)

	@ark.command(pass_context=True, name="backup")
	async def ark_backup(self):
		"""Creates a backup of the save and config files"""
		output = self.out("arkmanager backup", channel)

	@ark.command(pass_context=True, name="updatenow")
	@checks.is_owner()
	async def ark_updatenow(self):
		"""Updates without warning"""
		channel = ctx.message.channel
		output = self.out("arkmanager update --update-mods --backup", channel)

	@ark.command(pass_context=True, name="validate")
	@checks.is_owner()
	async def ark_validate(self):
		"""Validates the server files with steamcmd"""
		channel = ctx.message.channel
		await self.bot.say("Please note this can take a significant amount of time, please confirm you want to do this by replying Yes")
		answer = await self.bot.wait_for_message(timeout=30, author=user)
		if answer.content == "Yes":
			output = self.out("arkmanager update --validate", channel)
		else:
			await self.bot.edit_message(message, "Okay, validation cancelled")
			return

	@ark.command(pass_context=True, name="forceupdate")
	@checks.is_owner()
	async def ark_forceupdate(self):
		"""Updates without warning with the -force parameter"""
		channel = ctx.message.channel
		output = self.out("arkmanager update --update-mods --backup --force", channel)

	async def update_checker(self):
		"""Checks for updates automatically every hour"""
		while self is self.bot.get_cog("arkserver"):
			channel = self.bot.get_channel("330795712067665923")
			adminchannel = self.bot.get_channel("331076958425186305")
			if self.settings["AutoUpdate"] == True:
				output = self.out("arkmanager checkupdate", channel)
				if 'Your server is up to date!' in output:
					await self.bot.send_message(adminchannel,"No updates found.")
					await asyncio.sleep(3600)
				else:
					newoutput = self.out("arkmanager update --update-mods --backup --ifempty", adminchannel)
					if 'players are still connected' in newoutput:
						await self.bot.send_message(channel,"An update is available but players are still connected, automatic update will not continue.".format(newoutput))
						await asyncio.sleep(3600)
					else:
						await asyncio.sleep(3600)
			else:
				await self.bot.send_message(adminchannel,"Automatic updating is disabled, if the option is toggled on this might be because the server is already restarting or updating.")
				await asyncio.sleep(1800)

def check_folders():
	if not os.path.exists("data/arkserver"):
		print("Creating data/arkserver")
		os.makedirs("data/arkserver")

def check_files():
	files = {
		"settings.json": {"AutoUpdate": True}
	}

	for filename, value in files.items():
		if not os.path.isfile("data/arkserver/{}".format(filename)):
			print("Creating empty {}".format(filename))
			dataIO.save_json("data/arkserver/{}".format(filename), value)

def setup(bot):
	check_folders()
	check_files()
	n = arkserver(bot)
	loop = asyncio.get_event_loop()
	loop.create_task(n.update_checker())
	bot.add_cog(n)
<commit_msg>pass ctx<commit_after>import discord
from discord.ext import commands
from .utils import checks
from __main__ import send_cmd_help
from cogs.utils.dataIO import dataIO, fileIO

import json
import os
import asyncio
import subprocess

#def out(command):
#"""This function runs a shell script and collects the terminal response"""
#	result = run(command, stdout=PIPE, stderr=PIPE, universal_newlines=True, shell=True)
#	return result.stdout

class arkserver:
	"""Ark Server commands"""

	def __init__(self, bot):
		self.bot = bot
		self.settings = dataIO.load_json("data/arkserver/settings.json")

	async def out(self, command, channel):
		p = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
		for line in p.stdout.readlines():
			await self.bot.send_message(channel,"{0}".format(line))
		revtal = p.wait()

	@commands.group(pass_context=True)
	@checks.mod_or_permissions(manage_webhooks=True)
	async def ark(self, ctx):
		"""Commands related to Ark Server Management"""
		if ctx.invoked_subcommand is None:
			await self.bot.send_cmd_help(ctx)

	@ark.command(pass_context=True)
	async def checkupdate(self, ctx):
		"""Checks for ark updates - does not actually start the update"""
		channel = ctx.message.channel
		output = self.out("arkmanager checkupdate", channel)

	@ark.command(pass_context=True, name="stop")
	@checks.is_owner()
	async def ark_stop(self, ctx):
		"""Stops the Ark Server"""
		channel = ctx.message.channel
		output = self.out("arkmanager stop", channel)

	@ark.command(pass_context=True, name="toggle")
	@checks.is_owner()
	async def ark_toggle(self):
		"""Toggles autoupdating"""
		if self.settings["AutoUpdate"] == True:
			self.settings["AutoUpdate"] = False
			await self.bot.say("Automatic updating is now disabled.")
		else:
			self.settings["AutoUpdate"] = True
			await self.bot.say("Automatic server updating is now enabled.")
		dataIO.save_json('data/arkserver/settings.json', self.settings)

	@ark.command(pass_context=True, name="start")
	@checks.is_owner()
	async def ark_start(self, ctx):
		"""Starts the Ark Server"""
		channel = ctx.message.channel
		output = self.out("arkmanager start", channel)

	@ark.command(pass_context=True, name="status")
	async def ark_status(self, ctx):
		"""Checks the server status"""
		channel = ctx.message.channel
		output = await self.out("arkmanager status", channel)

	@ark.command(pass_context=True, name="restart")
	async def ark_restart(self, ctx):
		"""Restarts the ARK Server with a 60 second delay"""
		CurrentUpdating = self.settings["AutoUpdate"]
		channel = ctx.message.channel
		delay = 60
		self.settings["AutoUpdate"] = False #this makes sure autoupdate does not activate while the server is already busy
		await self.bot.say("Restarting in {0} seconds...".format(delay))
		text = "This server will restart in " + str(delay) + " seconds for maintenance."
		output = self.out('arkmanager broadcast' + ' ' + '"' + text + '"', channel)
		await asyncio.sleep(delay)
		output = out("arkmanager restart", channel)
		self.settings["AutoUpdate"] = CurrentUpdating #sets Updating back to the state it was before the command was run

	@ark.command(pass_context=True, name="update")
	async def ark_update(self, ctx, delay : int = 60):
		"""Stops the ARK Server, installs updates, then reboots"""
		CurrentUpdating = self.settings["AutoUpdate"]
		self.settings["AutoUpdate"] = False #this makes sure autoupdate does not activate while the server is already busy
		if delay > 600:
			delay = 600
		await self.bot.say("Restarting in {0} seconds...".format(delay))
		text = "This server will restart in " + str(delay) + " seconds for updates."
		output = self.out('arkmanager broadcast' + ' ' + '"' + text + '"')
		await asyncio.sleep(delay)
		output = self.out("arkmanager update --update-mods --backup")
		await self.bot.say("{0}".format(output))
		self.settings["AutoUpdate"] = CurrentUpdating #sets Updating back to the state it was before the command was run

	@ark.command(pass_context=True, name="save")
	async def ark_save(self, ctx):
		"""Saves the world state"""
		channel = ctx.message.channel
		output = self.out("arkmanager saveworld", channel)

	@ark.command(pass_context=True, name="backup")
	async def ark_backup(self, ctx):
		"""Creates a backup of the save and config files"""
		output = self.out("arkmanager backup", channel)

	@ark.command(pass_context=True, name="updatenow")
	@checks.is_owner()
	async def ark_updatenow(self, ctx):
		"""Updates without warning"""
		channel = ctx.message.channel
		output = self.out("arkmanager update --update-mods --backup", channel)

	@ark.command(pass_context=True, name="validate")
	@checks.is_owner()
	async def ark_validate(self, ctx):
		"""Validates the server files with steamcmd"""
		channel = ctx.message.channel
		await self.bot.say("Please note this can take a significant amount of time, please confirm you want to do this by replying Yes")
		answer = await self.bot.wait_for_message(timeout=30, author=user)
		if answer.content == "Yes":
			output = self.out("arkmanager update --validate", channel)
		else:
			await self.bot.edit_message(message, "Okay, validation cancelled")
			return

	@ark.command(pass_context=True, name="forceupdate")
	@checks.is_owner()
	async def ark_forceupdate(self, ctx):
		"""Updates without warning with the -force parameter"""
		channel = ctx.message.channel
		output = self.out("arkmanager update --update-mods --backup --force", channel)

	async def update_checker(self):
		"""Checks for updates automatically every hour"""
		while self is self.bot.get_cog("arkserver"):
			channel = self.bot.get_channel("330795712067665923")
			adminchannel = self.bot.get_channel("331076958425186305")
			if self.settings["AutoUpdate"] == True:
				output = self.out("arkmanager checkupdate", channel)
				if 'Your server is up to date!' in output:
					await self.bot.send_message(adminchannel,"No updates found.")
					await asyncio.sleep(3600)
				else:
					newoutput = self.out("arkmanager update --update-mods --backup --ifempty", adminchannel)
					if 'players are still connected' in newoutput:
						await self.bot.send_message(channel,"An update is available but players are still connected, automatic update will not continue.".format(newoutput))
						await asyncio.sleep(3600)
					else:
						await asyncio.sleep(3600)
			else:
				await self.bot.send_message(adminchannel,"Automatic updating is disabled, if the option is toggled on this might be because the server is already restarting or updating.")
				await asyncio.sleep(1800)

def check_folders():
	if not os.path.exists("data/arkserver"):
		print("Creating data/arkserver")
		os.makedirs("data/arkserver")

def check_files():
	files = {
		"settings.json": {"AutoUpdate": True}
	}

	for filename, value in files.items():
		if not os.path.isfile("data/arkserver/{}".format(filename)):
			print("Creating empty {}".format(filename))
			dataIO.save_json("data/arkserver/{}".format(filename), value)

def setup(bot):
	check_folders()
	check_files()
	n = arkserver(bot)
	loop = asyncio.get_event_loop()
	loop.create_task(n.update_checker())
	bot.add_cog(n)
<|endoftext|>


<commit_before>
#
"""
Functions that define and manipulate images. Images are just data and a World Coordinate System.
"""

import logging

from arl.image.operations import create_image_from_array

log = logging.getLogger(__name__)

def raster_iter(im, facets=2, **kwargs):
    """Create a raster_iter generator, returning images

    The WCS is adjusted appropriately for each raster element. Hence this is a coordinate-aware
    way to iterate through an image.

    Provided we don't break reference semantics, memory should be conserved

    To update the image in place:
        for r in raster(im, image_parititions=2)::
            r.data[...] = numpy.sqrt(r.data[...])

    :param facets: Number of image partitions on each axis (2)
    """

    log.info("raster: predicting using %d x %d image partitions" % (facets, facets))
    assert facets <= im.nheight, "Cannot have more raster elements than pixels"
    assert facets <= im.nwidth, "Cannot have more raster elements than pixels"
    assert im.nheight % facets == 0, "The partitions must exactly fill the image"
    assert im.nwidth % facets == 0, "The partitions must exactly fill the image"

    dx = int(im.nwidth // facets)
    dy = int(im.nheight // facets)
    log.info('raster: spacing of raster (%d, %d)' % (dx, dy))

    for y in range(0,im.nheight, dy):
        for x in range(0,im.nwidth, dx):
            log.debug('raster: partition (%d, %d) of (%d, %d)' %
                     (x//dx, y//dy, facets, facets))

            # Adjust WCS
            wcs = im.wcs.deepcopy()
            wcs.wcs.crpix[0] -= x
            wcs.wcs.crpix[1] -= y

            # Yield image from slice (reference!)
            yield create_image_from_array(im.data[..., y:y+dy, x:x+dx], wcs)
<commit_msg>Image iterator doc fix<commit_after>
#
"""
Functions that define and manipulate images. Images are just data and a World Coordinate System.
"""

import logging

from arl.image.operations import create_image_from_array

log = logging.getLogger(__name__)

def raster_iter(im, facets=2, **kwargs):
    """Create a raster_iter generator, returning images

    The WCS is adjusted appropriately for each raster element. Hence this is a coordinate-aware
    way to iterate through an image.

    Provided we don't break reference semantics, memory should be conserved

    To update the image in place:
        for r in raster(im, facets=2)::
            r.data[...] = numpy.sqrt(r.data[...])

    :param im: Image
    :param facets: Number of image partitions on each axis (2)
    """

    log.info("raster: predicting using %d x %d image partitions" % (facets, facets))
    assert facets <= im.nheight, "Cannot have more raster elements than pixels"
    assert facets <= im.nwidth, "Cannot have more raster elements than pixels"
    assert im.nheight % facets == 0, "The partitions must exactly fill the image"
    assert im.nwidth % facets == 0, "The partitions must exactly fill the image"

    dx = int(im.nwidth // facets)
    dy = int(im.nheight // facets)
    log.info('raster: spacing of raster (%d, %d)' % (dx, dy))

    for y in range(0,im.nheight, dy):
        for x in range(0,im.nwidth, dx):
            log.debug('raster: partition (%d, %d) of (%d, %d)' %
                     (x//dx, y//dy, facets, facets))

            # Adjust WCS
            wcs = im.wcs.deepcopy()
            wcs.wcs.crpix[0] -= x
            wcs.wcs.crpix[1] -= y

            # Yield image from slice (reference!)
            yield create_image_from_array(im.data[..., y:y+dy, x:x+dx], wcs)
<|endoftext|>


<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-

# -----------------------------------------------------------------------------------------------------------------------
# INFO:
# -----------------------------------------------------------------------------------------------------------------------

"""
Author: Evan Hubinger
License: Apache 2.0
Description: Coconut installation requirements.
"""

# -----------------------------------------------------------------------------------------------------------------------
# IMPORTS:
# -----------------------------------------------------------------------------------------------------------------------

from coconut.root import *  # NOQA

import sys
import time

from coconut.constants import (
    ver_str_to_tuple,
    ver_tuple_to_str,
    get_next_version,
    all_reqs,
    min_versions,
    max_versions,
    pinned_reqs,
    PYPY,
    CPYTHON,
    PY34,
    JUST_PY36,
    IPY,
    WINDOWS,
    PURE_PYTHON,
    requests_sleep_times,
)

# -----------------------------------------------------------------------------------------------------------------------
# CONSTANTS:
# -----------------------------------------------------------------------------------------------------------------------

try:
    import setuptools  # this import is expensive, so we keep it out of constants
    setuptools_version = tuple(int(x) for x in setuptools.__version__.split("."))
    using_modern_setuptools = setuptools_version >= (18,)
    supports_env_markers = setuptools_version >= (36, 2)
except Exception:
    using_modern_setuptools = False
    supports_env_markers = False

# -----------------------------------------------------------------------------------------------------------------------
# UTILITIES:
# -----------------------------------------------------------------------------------------------------------------------

def get_base_req(req):
    """Get the name of the required package for the given requirement."""
    if isinstance(req, tuple):
        req = req[0]
    return req.split(":", 1)[0]

def get_reqs(which):
    """Gets requirements from all_reqs with versions."""
    reqs = []
    for req in all_reqs[which]:
        use_req = True
        req_str = get_base_req(req) + ">=" + ver_tuple_to_str(min_versions[req])
        if req in max_versions:
            max_ver = max_versions[req]
            if max_ver is None:
                max_ver = get_next_version(min_versions[req])
            req_str += ",<" + ver_tuple_to_str(max_ver)
        env_marker = req[1] if isinstance(req, tuple) else None
        if env_marker:
            markers = []
            for mark in env_marker.split(";"):
                if mark == "py2":
                    if supports_env_markers:
                        markers.append("python_version<'3'")
                    elif not PY2:
                        use_req = False
                        break
                elif mark == "py3":
                    if supports_env_markers:
                        markers.append("python_version>='3'")
                    elif PY2:
                        use_req = False
                        break
                elif mark.startswith("py3") and len(mark) == len("py3") + 1:
                    ver = int(mark[len("py3"):])
                    if supports_env_markers:
                        markers.append("python_version>='3.{ver}'".format(ver=ver))
                    elif sys.version_info < (3, ver):
                        use_req = False
                        break
                elif mark == "cpy":
                    if supports_env_markers:
                        markers.append("platform_python_implementation=='CPython'")
                    elif not CPYTHON:
                        use_req = False
                        break
                else:
                    raise ValueError("unknown env marker " + repr(mark))
            if markers:
                req_str += ";" + " and ".join(markers)
        if use_req:
            reqs.append(req_str)
    return reqs

def uniqueify(reqs):
    """Make a list of requirements unique."""
    return list(set(reqs))

def uniqueify_all(init_reqs, *other_reqs):
    """Find the union of all the given requirements."""
    union = set(init_reqs)
    for reqs in other_reqs:
        union.update(reqs)
    return list(union)

def unique_wrt(reqs, main_reqs):
    """Ensures reqs doesn't contain anything in main_reqs."""
    return list(set(reqs) - set(main_reqs))

def everything_in(req_dict):
    """Gets all requirements in a requirements dict."""
    return uniqueify(req for req_list in req_dict.values() for req in req_list)

# -----------------------------------------------------------------------------------------------------------------------
# SETUP:
# -----------------------------------------------------------------------------------------------------------------------

requirements = []

extras = {
    "jupyter": get_reqs("jupyter"),
    "watch": get_reqs("watch"),
    "jobs": get_reqs("jobs"),
    "mypy": get_reqs("mypy"),
    "asyncio": get_reqs("asyncio"),
}

extras["all"] = everything_in(extras)

extras.update({
    "ipython": extras["jupyter"],
    "docs": unique_wrt(get_reqs("docs"), requirements),
    "tests": uniqueify_all(
        get_reqs("tests"),
        get_reqs("purepython"),
        extras["jobs"] if not PYPY else [],
        extras["jupyter"] if IPY else [],
        extras["mypy"] if PY34 and not WINDOWS and not PYPY else [],
        extras["asyncio"] if not PY34 and not PYPY else [],
    ),
})

extras["dev"] = uniqueify_all(
    everything_in(extras),
    get_reqs("dev"),
)

if PURE_PYTHON:
    # override necessary for readthedocs
    requirements += get_reqs("purepython")
elif supports_env_markers:
    # modern method
    extras[":platform_python_implementation=='CPython'"] = get_reqs("cpython")
    extras[":platform_python_implementation!='CPython'"] = get_reqs("purepython")
else:
    # old method
    if CPYTHON:
        requirements += get_reqs("cpython")
    else:
        requirements += get_reqs("purepython")

if using_modern_setuptools:
    # modern method
    extras[":python_version<'2.7'"] = get_reqs("py26")
    extras[":python_version>='2.7'"] = get_reqs("non-py26")
    extras[":python_version<'3'"] = get_reqs("py2")
    extras[":python_version>='3'"] = get_reqs("py3")
    extras[":python_version=='3.6.*'"] = get_reqs("just-py36")

else:
    # old method
    if PY26:
        requirements += get_reqs("py26")
    else:
        requirements += get_reqs("non-py26")
    if PY2:
        requirements += get_reqs("py2")
    else:
        requirements += get_reqs("py3")
    if JUST_PY36:
        requirements += get_reqs("just-py36")

# -----------------------------------------------------------------------------------------------------------------------
# MAIN:
# -----------------------------------------------------------------------------------------------------------------------

def all_versions(req):
    """Get all versions of req from PyPI."""
    import requests  # expensive
    url = "https://pypi.python.org/pypi/" + get_base_req(req) + "/json"
    for i, sleep_time in enumerate(requests_sleep_times):
        time.sleep(sleep_time)
        try:
            result = requests.get(url)
        except Exception:
            if i == len(requests_sleep_times) - 1:
                print("Error accessing:", url)
                raise
            elif i > 0:
                print("Error accessing:", url, "(retrying)")
        else:
            break
    return tuple(result.json()["releases"].keys())

def newer(new_ver, old_ver, strict=False):
    """Determines if the first version tuple is newer than the second.
    True if newer; False if older."""
    if old_ver == new_ver or old_ver + (0,) == new_ver:
        return False
    for n, o in zip(new_ver, old_ver):
        if not isinstance(n, int):
            o = str(o)
        if o < n:
            return True
        elif o > n:
            return False
    return not strict

def print_new_versions(strict=False):
    """Prints new requirement versions."""
    new_updates = []
    same_updates = []
    pinned_updates = []
    for req in everything_in(all_reqs):
        new_versions = []
        same_versions = []
        for ver_str in all_versions(req):
            if newer(ver_str_to_tuple(ver_str), min_versions[req], strict=True):
                new_versions.append(ver_str)
            elif not strict and newer(ver_str_to_tuple(ver_str), min_versions[req]):
                same_versions.append(ver_str)
        if isinstance(req, tuple):
            base_req, env_marker = req
        else:
            base_req, env_marker = req, None
        update_str = (
            base_req + (" (" + env_marker + ")" if env_marker else "")
            + " = " + ver_tuple_to_str(min_versions[req])
            + " -> " + ", ".join(new_versions + ["(" + v + ")" for v in same_versions])
        )
        if req in pinned_reqs:
            pinned_updates.append(update_str)
        elif new_versions:
            new_updates.append(update_str)
        elif same_versions:
            same_updates.append(update_str)
    print("\n".join(new_updates))
    print()
    print("\n".join(same_updates))
    print()
    print("\n".join(pinned_updates))

if __name__ == "__main__":
    print_new_versions()
<commit_msg>[fix] Error on non-numeric patch version<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-

# -----------------------------------------------------------------------------------------------------------------------
# INFO:
# -----------------------------------------------------------------------------------------------------------------------

"""
Author: Evan Hubinger
License: Apache 2.0
Description: Coconut installation requirements.
"""

# -----------------------------------------------------------------------------------------------------------------------
# IMPORTS:
# -----------------------------------------------------------------------------------------------------------------------

from coconut.root import *  # NOQA

import sys
import time

from coconut.constants import (
    ver_str_to_tuple,
    ver_tuple_to_str,
    get_next_version,
    all_reqs,
    min_versions,
    max_versions,
    pinned_reqs,
    PYPY,
    CPYTHON,
    PY34,
    JUST_PY36,
    IPY,
    WINDOWS,
    PURE_PYTHON,
    requests_sleep_times,
)

# -----------------------------------------------------------------------------------------------------------------------
# CONSTANTS:
# -----------------------------------------------------------------------------------------------------------------------

try:
    import setuptools  # this import is expensive, so we keep it out of constants
    setuptools_version = tuple(int(x) for x in setuptools.__version__.split(".")[:2])
    using_modern_setuptools = setuptools_version >= (18,)
    supports_env_markers = setuptools_version >= (36, 2)
except Exception:
    using_modern_setuptools = False
    supports_env_markers = False

# -----------------------------------------------------------------------------------------------------------------------
# UTILITIES:
# -----------------------------------------------------------------------------------------------------------------------

def get_base_req(req):
    """Get the name of the required package for the given requirement."""
    if isinstance(req, tuple):
        req = req[0]
    return req.split(":", 1)[0]

def get_reqs(which):
    """Gets requirements from all_reqs with versions."""
    reqs = []
    for req in all_reqs[which]:
        use_req = True
        req_str = get_base_req(req) + ">=" + ver_tuple_to_str(min_versions[req])
        if req in max_versions:
            max_ver = max_versions[req]
            if max_ver is None:
                max_ver = get_next_version(min_versions[req])
            req_str += ",<" + ver_tuple_to_str(max_ver)
        env_marker = req[1] if isinstance(req, tuple) else None
        if env_marker:
            markers = []
            for mark in env_marker.split(";"):
                if mark == "py2":
                    if supports_env_markers:
                        markers.append("python_version<'3'")
                    elif not PY2:
                        use_req = False
                        break
                elif mark == "py3":
                    if supports_env_markers:
                        markers.append("python_version>='3'")
                    elif PY2:
                        use_req = False
                        break
                elif mark.startswith("py3") and len(mark) == len("py3") + 1:
                    ver = int(mark[len("py3"):])
                    if supports_env_markers:
                        markers.append("python_version>='3.{ver}'".format(ver=ver))
                    elif sys.version_info < (3, ver):
                        use_req = False
                        break
                elif mark == "cpy":
                    if supports_env_markers:
                        markers.append("platform_python_implementation=='CPython'")
                    elif not CPYTHON:
                        use_req = False
                        break
                else:
                    raise ValueError("unknown env marker " + repr(mark))
            if markers:
                req_str += ";" + " and ".join(markers)
        if use_req:
            reqs.append(req_str)
    return reqs

def uniqueify(reqs):
    """Make a list of requirements unique."""
    return list(set(reqs))

def uniqueify_all(init_reqs, *other_reqs):
    """Find the union of all the given requirements."""
    union = set(init_reqs)
    for reqs in other_reqs:
        union.update(reqs)
    return list(union)

def unique_wrt(reqs, main_reqs):
    """Ensures reqs doesn't contain anything in main_reqs."""
    return list(set(reqs) - set(main_reqs))

def everything_in(req_dict):
    """Gets all requirements in a requirements dict."""
    return uniqueify(req for req_list in req_dict.values() for req in req_list)

# -----------------------------------------------------------------------------------------------------------------------
# SETUP:
# -----------------------------------------------------------------------------------------------------------------------

requirements = []

extras = {
    "jupyter": get_reqs("jupyter"),
    "watch": get_reqs("watch"),
    "jobs": get_reqs("jobs"),
    "mypy": get_reqs("mypy"),
    "asyncio": get_reqs("asyncio"),
}

extras["all"] = everything_in(extras)

extras.update({
    "ipython": extras["jupyter"],
    "docs": unique_wrt(get_reqs("docs"), requirements),
    "tests": uniqueify_all(
        get_reqs("tests"),
        get_reqs("purepython"),
        extras["jobs"] if not PYPY else [],
        extras["jupyter"] if IPY else [],
        extras["mypy"] if PY34 and not WINDOWS and not PYPY else [],
        extras["asyncio"] if not PY34 and not PYPY else [],
    ),
})

extras["dev"] = uniqueify_all(
    everything_in(extras),
    get_reqs("dev"),
)

if PURE_PYTHON:
    # override necessary for readthedocs
    requirements += get_reqs("purepython")
elif supports_env_markers:
    # modern method
    extras[":platform_python_implementation=='CPython'"] = get_reqs("cpython")
    extras[":platform_python_implementation!='CPython'"] = get_reqs("purepython")
else:
    # old method
    if CPYTHON:
        requirements += get_reqs("cpython")
    else:
        requirements += get_reqs("purepython")

if using_modern_setuptools:
    # modern method
    extras[":python_version<'2.7'"] = get_reqs("py26")
    extras[":python_version>='2.7'"] = get_reqs("non-py26")
    extras[":python_version<'3'"] = get_reqs("py2")
    extras[":python_version>='3'"] = get_reqs("py3")
    extras[":python_version=='3.6.*'"] = get_reqs("just-py36")

else:
    # old method
    if PY26:
        requirements += get_reqs("py26")
    else:
        requirements += get_reqs("non-py26")
    if PY2:
        requirements += get_reqs("py2")
    else:
        requirements += get_reqs("py3")
    if JUST_PY36:
        requirements += get_reqs("just-py36")

# -----------------------------------------------------------------------------------------------------------------------
# MAIN:
# -----------------------------------------------------------------------------------------------------------------------

def all_versions(req):
    """Get all versions of req from PyPI."""
    import requests  # expensive
    url = "https://pypi.python.org/pypi/" + get_base_req(req) + "/json"
    for i, sleep_time in enumerate(requests_sleep_times):
        time.sleep(sleep_time)
        try:
            result = requests.get(url)
        except Exception:
            if i == len(requests_sleep_times) - 1:
                print("Error accessing:", url)
                raise
            elif i > 0:
                print("Error accessing:", url, "(retrying)")
        else:
            break
    return tuple(result.json()["releases"].keys())

def newer(new_ver, old_ver, strict=False):
    """Determines if the first version tuple is newer than the second.
    True if newer; False if older."""
    if old_ver == new_ver or old_ver + (0,) == new_ver:
        return False
    for n, o in zip(new_ver, old_ver):
        if not isinstance(n, int):
            o = str(o)
        if o < n:
            return True
        elif o > n:
            return False
    return not strict

def print_new_versions(strict=False):
    """Prints new requirement versions."""
    new_updates = []
    same_updates = []
    pinned_updates = []
    for req in everything_in(all_reqs):
        new_versions = []
        same_versions = []
        for ver_str in all_versions(req):
            if newer(ver_str_to_tuple(ver_str), min_versions[req], strict=True):
                new_versions.append(ver_str)
            elif not strict and newer(ver_str_to_tuple(ver_str), min_versions[req]):
                same_versions.append(ver_str)
        if isinstance(req, tuple):
            base_req, env_marker = req
        else:
            base_req, env_marker = req, None
        update_str = (
            base_req + (" (" + env_marker + ")" if env_marker else "")
            + " = " + ver_tuple_to_str(min_versions[req])
            + " -> " + ", ".join(new_versions + ["(" + v + ")" for v in same_versions])
        )
        if req in pinned_reqs:
            pinned_updates.append(update_str)
        elif new_versions:
            new_updates.append(update_str)
        elif same_versions:
            same_updates.append(update_str)
    print("\n".join(new_updates))
    print()
    print("\n".join(same_updates))
    print()
    print("\n".join(pinned_updates))

if __name__ == "__main__":
    print_new_versions()
<|endoftext|>


<commit_before>import tempfile
import unittest
import unittest.mock

from . import profile
from . import test_helper

@unittest.mock.patch.object(
  profile.Profile,
  'generate',
  autospec=True,
  )
@unittest.mock.patch.object(
  profile.Profile,
  '__abstractmethods__',
  new=set(),
  )
class TestProfile(unittest.TestCase):
  def setUp(self):
    self.dir = tempfile.TemporaryDirectory()

  def tearDown(self):
    self.dir.cleanup()

  def test_generate_all(self, mock_generate):
    p = profile.Profile(self.dir.name, None)
    p0 = profile.Profile(self.dir.name, p)
    p00 = profile.Profile(self.dir.name, p0)
    p1 = profile.Profile(self.dir.name, p)

    p.generate_all()

    self.assertEqual(
      mock_generate.mock_calls,
      [unittest.mock.call(x) for x in (p, p0, p00, p1)])

<commit_msg>Add tests for profile.FilterProfile.<commit_after>import os
import tempfile
import unittest
import unittest.mock

from . import profile
from . import test_helper

@unittest.mock.patch.object(
  profile.Profile,
  'generate',
  autospec=True,
  )
@unittest.mock.patch.object(
  profile.Profile,
  '__abstractmethods__',
  new=set(),
  )
class TestProfile(unittest.TestCase):
  def setUp(self):
    self.dir = tempfile.TemporaryDirectory()

  def tearDown(self):
    self.dir.cleanup()

  def test_generate_all(self, mock_generate):
    p = profile.Profile(self.dir.name, None)
    p0 = profile.Profile(self.dir.name, p)
    p00 = profile.Profile(self.dir.name, p0)
    p1 = profile.Profile(self.dir.name, p)

    p.generate_all()

    self.assertEqual(
      mock_generate.mock_calls,
      [unittest.mock.call(x) for x in (p, p0, p00, p1)])

class TestFilterProfile(
    unittest.TestCase,
    test_helper.SrcDstDirMixin,
    ):
  def setUp(self):
    test_helper.SrcDstDirMixin.setUp(self)

  def tearDown(self):
    test_helper.SrcDstDirMixin.tearDown(self)

  def test_clean_ok(self):
    os.mkdir(os.path.join(self.dst_path(), 'dir'))
    os.mkdir(os.path.join(self.dst_path(), 'dir', 'dir'))
    os.symlink(
      '/dev/null',
      os.path.join(self.dst_path(), 'dir', 'dir', 'file'))
    os.symlink(
      '/dev/null',
      os.path.join(self.dst_path(), 'file'))
    self.assertNotEqual(os.listdir(self.dst_path()), [])

    root = profile.RootProfile(top_dir=self.src_path())
    p = profile.FilterProfile(
      top_dir=self.dst_path(),
      parent=root,
      select_cb=lambda profile, dir, contents: contents,
      )
    p.generate()

    self.assertEqual(os.listdir(self.dst_path()), [])

  def test_clean_error_file(self):
    open(os.path.join(self.dst_path(), 'file'), 'w').close()

    root = profile.RootProfile(top_dir=self.src_path())
    p = profile.FilterProfile(
      top_dir=self.dst_path(),
      parent=root,
      select_cb=lambda profile, dir, contents: contents,
      )

    self.assertRaisesRegex(
      RuntimeError,
      '^Cannot clean ',
      p.generate,
      )

    self.assertTrue(os.path.isfile(
      os.path.join(self.dst_path(), 'file')))

  def test_empty_noop(self):
    root = profile.RootProfile(top_dir=self.src_path())

    select_cb = unittest.mock.Mock(return_value=[])
    p = profile.FilterProfile(
      top_dir=self.dst_path(),
      parent=root,
      select_cb=select_cb,
      )

    p.generate()

    select_cb.assert_called_once_with(p, '', [])

    self.assertEqual(os.listdir(self.dst_path()), [])

  def test_select_none(self):
    os.mkdir(os.path.join(self.src_path(), 'dir'))
    os.mkdir(os.path.join(self.src_path(), 'dir', 'dir'))
    open(os.path.join(self.src_path(), 'dir', 'dir', 'file'), 'w').close()
    open(os.path.join(self.src_path(), 'file'), 'w').close()

    root = profile.RootProfile(top_dir=self.src_path())

    select_cb = unittest.mock.Mock(return_value=[])
    p = profile.FilterProfile(
      top_dir=self.dst_path(),
      parent=root,
      select_cb=select_cb,
      )

    p.generate()

    select_cb.assert_called_once_with(p, '', unittest.mock.ANY)

    self.assertEqual(os.listdir(self.dst_path()), [])

  def test_select_all(self):
    os.mkdir(os.path.join(self.src_path(), 'dir'))
    os.mkdir(os.path.join(self.src_path(), 'dir', 'dir'))
    open(os.path.join(self.src_path(), 'dir', 'dir', 'file'), 'w').close()
    open(os.path.join(self.src_path(), 'file'), 'w').close()

    root = profile.RootProfile(top_dir=self.src_path())

    select_cb = unittest.mock.Mock(
      wraps=lambda profile, dir, contents: contents)
    p = profile.FilterProfile(
      top_dir=self.dst_path(),
      parent=root,
      select_cb=select_cb,
      )

    p.generate()

    self.assertEqual(
      select_cb.mock_calls,
      [
        unittest.mock.call(p, '', unittest.mock.ANY),
        unittest.mock.call(p, 'dir', unittest.mock.ANY),
        unittest.mock.call(p, 'dir/dir', unittest.mock.ANY),
        ],
      )

    self.assertEqual(
      frozenset(os.listdir(self.dst_path())),
      {'dir', 'file'})
    self.assertEqual(
      frozenset(os.listdir(os.path.join(self.src_path(), 'dir'))),
      {'dir'})
    self.assertEqual(
      frozenset(os.listdir(os.path.join(self.src_path(), 'dir', 'dir'))),
      {'file'})

    self.assertEqual(
      test_helper.get_preserved_attrs(
        os.path.join(self.src_path(), 'dir')),
      test_helper.get_preserved_attrs(
        os.path.join(self.dst_path(), 'dir')),
      )
    self.assertEqual(
      test_helper.get_preserved_attrs(
        os.path.join(self.src_path(), 'dir', 'dir')),
      test_helper.get_preserved_attrs(
        os.path.join(self.dst_path(), 'dir', 'dir')),
      )

    self.assertEqual(
      test_helper.symlink_pointee_abspath(
        os.path.join(self.dst_path(), 'file')),
      os.path.abspath(
        os.path.join(self.src_path(), 'file')),
      )
    self.assertEqual(
      test_helper.symlink_pointee_abspath(
        os.path.join(self.dst_path(), 'dir', 'dir', 'file')),
      os.path.abspath(
        os.path.join(self.src_path(), 'dir', 'dir', 'file')),
      )

  def test_select_dir_but_not_its_contents(self):
    os.mkdir(os.path.join(self.src_path(), 'dir'))
    open(os.path.join(self.src_path(), 'dir', 'file'), 'w').close()

    root = profile.RootProfile(top_dir=self.src_path())

    select_cb = unittest.mock.Mock(
      wraps=lambda profile, dir, contents:
        contents if dir == '' else [],
      )
    p = profile.FilterProfile(
      top_dir=self.dst_path(),
      parent=root,
      select_cb=select_cb,
      )

    p.generate()

    self.assertEqual(
      select_cb.mock_calls,
      [
        unittest.mock.call(p, '', unittest.mock.ANY),
        unittest.mock.call(p, 'dir', unittest.mock.ANY),
        ],
      )

    self.assertEqual(os.listdir(self.dst_path()), [])

  def test_rename(self):
    open(os.path.join(self.src_path(), 'file'), 'w').close()

    root = profile.RootProfile(top_dir=self.src_path())

    p = profile.FilterProfile(
      top_dir=self.dst_path(),
      parent=root,
      select_cb=
        lambda profile, dir, contents:
          [(x, 'renamed') for x in contents],
      )

    p.generate()

    self.assertEqual(os.listdir(self.dst_path()), ['renamed'])

    self.assertEqual(
      test_helper.symlink_pointee_abspath(
        os.path.join(self.dst_path(), 'renamed')),
      os.path.abspath(
        os.path.join(self.src_path(), 'file')),
      )

  def test_rename_dir_error(self):
    os.mkdir(os.path.join(self.src_path(), 'dir'))

    root = profile.RootProfile(top_dir=self.src_path())

    p = profile.FilterProfile(
      top_dir=self.dst_path(),
      parent=root,
      select_cb=
        lambda profile, dir, contents:
          [(x, 'renamed') for x in contents],
      )

    self.assertRaisesRegex(
      NotImplementedError,
      '^Renaming directories is not supported: ',
      p.generate,
      )

  def test_rename_across_dir_error(self):
    os.mkdir(os.path.join(self.src_path(), 'dir'))
    open(os.path.join(self.src_path(), 'file'), 'w').close()

    root = profile.RootProfile(top_dir=self.src_path())

    def select_cb(profile, dir, contents):
      ret = []
      for entry in contents:
        if entry.name.endswith('file'):
          ret.append((entry, 'dir/file'))
        else:
          ret.append(entry)
      return ret
    p = profile.FilterProfile(
      top_dir=self.dst_path(),
      parent=root,
      select_cb=select_cb,
      )

    self.assertRaisesRegex(
      NotImplementedError,
      '^Renaming across dirs is not supported: ',
      p.generate,
      )
<|endoftext|>


<commit_before>from __future__ import unicode_literals

import sys
# TODO: Remove when support for Python 2.6 is dropped
if sys.version_info >= (2, 7):
    from unittest import skipUnless
else:
    from django.utils.unittest import skipUnless

from django import forms
from django.core.exceptions import ValidationError
from django.db import models
from django.test import SimpleTestCase

from ..fields import RGBColorField, RGB_REGEX
from ..widgets import ColorFieldWidget

class TestRBGColorField(SimpleTestCase):
    def setUp(self):
        self.field = RGBColorField(default='#123445')

    def test_validate_fails(self):
        self.assertRaises(ValidationError, self.field.clean, '', None)
        self.assertRaises(ValidationError, self.field.clean, '12', None)
        self.assertRaises(ValidationError, self.field.clean, 'GGGGGG', None)
        self.assertRaises(ValidationError, self.field.clean, '#GGGGGG', None)
        self.assertRaises(ValidationError, self.field.clean, 'GGG', None)
        self.assertRaises(ValidationError, self.field.clean, '#GGG', None)
        self.assertRaises(ValidationError, self.field.clean, '#1234567', None)

        self.assertRaisesMessage(
            ValidationError,
            'Ensure this value has at most 7 characters (it has 8).',
            self.field.clean, '#1234567', None
        )

    def test_validate_passes(self):
        self.assertEqual('#123445', self.field.clean('#123445', None))
        self.assertEqual('#123', self.field.clean('#123', None))
        self.assertEqual('#ABCDEF', self.field.clean('#ABCDEF', None))
        self.assertEqual('ABCDEF', self.field.clean('ABCDEF', None))
        self.assertEqual('123', self.field.clean('123', None))
        self.assertEqual('ABC', self.field.clean('ABC', None))

    def test_south_field_triple(self):
        path, args, kwargs = self.field.south_field_triple()
        module, cls = path.rsplit('.', 1)
        field_cls = getattr(sys.modules[module], cls)
        field_args = [eval(arg) for arg in args]
        field_kwargs = dict(
            (key, eval(kwarg)) for key, kwarg in kwargs.items()
        )
        field = field_cls(*field_args, **field_kwargs)
        self.assertIsInstance(field, self.field.__class__)
        self.assertEqual(field.default, self.field.default)

    @skipUnless(hasattr(models.Field, 'deconstruct'),
                'Unavailable field deconstruction.')
    def test_deconstruct(self):
        name, path, args, kwargs = self.field.deconstruct()
        self.assertIsNone(name)
        module, cls = path.rsplit('.', 1)
        field_class = getattr(sys.modules[module], cls)
        field_instance = field_class(*args, **kwargs)
        self.assertIsInstance(field_instance, self.field.__class__)

    def test_formfield(self):
        formfield = self.field.formfield()
        self.assertIsInstance(formfield, forms.RegexField)
        self.assertIsInstance(formfield.widget, ColorFieldWidget)
        self.assertEqual(formfield.regex, RGB_REGEX)

class TestColorFieldWidget(SimpleTestCase):
    def test_render_with_id(self):
        widget = ColorFieldWidget()
        self.assertIn('<input id="id_color" name="test" type="color" value="#123456" />',
                      widget.render('test', '#123456', {'id': 'id_color'}))
        self.assertIn('''<script type="text/javascript">
                    (function($){
                        $(document).ready(function(){
                            $('#id_color').each(function(i, elm){
                                // Make sure html5 color element is not replaced
                                if (elm.type != 'color') $(elm).colorPicker();
                            });
                        });
                    })('django' in window ? django.jQuery: jQuery);
                </script>
                ''', widget.render('test', '#123456', {'id': 'id_color'}))

    def test_render_no_id(self):
        widget = ColorFieldWidget()
        self.assertIn('<input id="id_test" name="test" type="color" value="#123456" />',
                      widget.render('test', '#123456'))
        self.assertIn('''<script type="text/javascript">
                    (function($){
                        $(document).ready(function(){
                            $('#id_test').each(function(i, elm){
                                // Make sure html5 color element is not replaced
                                if (elm.type != 'color') $(elm).colorPicker();
                            });
                        });
                    })('django' in window ? django.jQuery: jQuery);
                </script>
                ''', widget.render('test', '#123456'))
<commit_msg>Only run South related tests if it is installed.<commit_after>from __future__ import unicode_literals

import sys
# TODO: Remove when support for Python 2.6 is dropped
if sys.version_info >= (2, 7):
    from unittest import skipIf, skipUnless
else:
    from django.utils.unittest import skipIf, skipUnless

from django import forms
from django.core.exceptions import ValidationError
from django.db import models
from django.test import SimpleTestCase

from ..fields import RGBColorField, RGB_REGEX
from ..widgets import ColorFieldWidget

try:
    import south
except ImportError:
    south = None

class TestRBGColorField(SimpleTestCase):
    def setUp(self):
        self.field = RGBColorField(default='#123445')

    def test_validate_fails(self):
        self.assertRaises(ValidationError, self.field.clean, '', None)
        self.assertRaises(ValidationError, self.field.clean, '12', None)
        self.assertRaises(ValidationError, self.field.clean, 'GGGGGG', None)
        self.assertRaises(ValidationError, self.field.clean, '#GGGGGG', None)
        self.assertRaises(ValidationError, self.field.clean, 'GGG', None)
        self.assertRaises(ValidationError, self.field.clean, '#GGG', None)
        self.assertRaises(ValidationError, self.field.clean, '#1234567', None)

        self.assertRaisesMessage(
            ValidationError,
            'Ensure this value has at most 7 characters (it has 8).',
            self.field.clean, '#1234567', None
        )

    def test_validate_passes(self):
        self.assertEqual('#123445', self.field.clean('#123445', None))
        self.assertEqual('#123', self.field.clean('#123', None))
        self.assertEqual('#ABCDEF', self.field.clean('#ABCDEF', None))
        self.assertEqual('ABCDEF', self.field.clean('ABCDEF', None))
        self.assertEqual('123', self.field.clean('123', None))
        self.assertEqual('ABC', self.field.clean('ABC', None))

    @skipIf(south is None, 'South is not installed.')
    def test_south_field_triple(self):
        path, args, kwargs = self.field.south_field_triple()
        module, cls = path.rsplit('.', 1)
        field_cls = getattr(sys.modules[module], cls)
        field_args = [eval(arg) for arg in args]
        field_kwargs = dict(
            (key, eval(kwarg)) for key, kwarg in kwargs.items()
        )
        field = field_cls(*field_args, **field_kwargs)
        self.assertIsInstance(field, self.field.__class__)
        self.assertEqual(field.default, self.field.default)

    @skipUnless(hasattr(models.Field, 'deconstruct'),
                'Unavailable field deconstruction.')
    def test_deconstruct(self):
        name, path, args, kwargs = self.field.deconstruct()
        self.assertIsNone(name)
        module, cls = path.rsplit('.', 1)
        field_class = getattr(sys.modules[module], cls)
        field_instance = field_class(*args, **kwargs)
        self.assertIsInstance(field_instance, self.field.__class__)

    def test_formfield(self):
        formfield = self.field.formfield()
        self.assertIsInstance(formfield, forms.RegexField)
        self.assertIsInstance(formfield.widget, ColorFieldWidget)
        self.assertEqual(formfield.regex, RGB_REGEX)

class TestColorFieldWidget(SimpleTestCase):
    def test_render_with_id(self):
        widget = ColorFieldWidget()
        self.assertIn('<input id="id_color" name="test" type="color" value="#123456" />',
                      widget.render('test', '#123456', {'id': 'id_color'}))
        self.assertIn('''<script type="text/javascript">
                    (function($){
                        $(document).ready(function(){
                            $('#id_color').each(function(i, elm){
                                // Make sure html5 color element is not replaced
                                if (elm.type != 'color') $(elm).colorPicker();
                            });
                        });
                    })('django' in window ? django.jQuery: jQuery);
                </script>
                ''', widget.render('test', '#123456', {'id': 'id_color'}))

    def test_render_no_id(self):
        widget = ColorFieldWidget()
        self.assertIn('<input id="id_test" name="test" type="color" value="#123456" />',
                      widget.render('test', '#123456'))
        self.assertIn('''<script type="text/javascript">
                    (function($){
                        $(document).ready(function(){
                            $('#id_test').each(function(i, elm){
                                // Make sure html5 color element is not replaced
                                if (elm.type != 'color') $(elm).colorPicker();
                            });
                        });
                    })('django' in window ? django.jQuery: jQuery);
                </script>
                ''', widget.render('test', '#123456'))
<|endoftext|>


<commit_before>from __future__ import absolute_import, division, print_function, unicode_literals

import contextlib
import os
import os.path
import sys
import threading
import time
import traceback

from echomesh.command import Score
from echomesh.config import Config
from echomesh.graphics import Display
from echomesh.network import PeerSocket
from echomesh.sound import Microphone
from echomesh.sound import SetOutput
from echomesh.util import Log
from echomesh.util.thread import Closer
from echomesh.util.thread import Keyboard

LOGGER = Log.logger(__name__)
ECHOMESH = None

class Echomesh(Closer.Closer):
  INSTANCE = None

  def __init__(self):
    super(Echomesh, self).__init__()
    if Echomesh.INSTANCE:
      LOGGER.error('There is more than one instance of Echomesh')
    else:
      Echomesh.INSTANCE = self

    self.socket = PeerSocket.PeerSocket(self)
    self.score = Score.make_score()

    self.add_openable_mutual(self.socket,
                             Keyboard.keyboard(self),
                             Display.display(self),
                             Microphone.microphone(self._mic_event),
                             self.score)

  def send(self, **data):
    self.socket.send(data)

  def receive(self, event):
    return self.score.receive_event(event)

  def start(self):
    super(Echomesh, self).start()
    self.join()

  def _mic_event(self, level):
    self.send(type='event', event='mic', key=level)

  # TODO: these next methods don't work any more.
  def remove_local(self):
    try:
      Config.remove_local()
      self.microphone.set_config()
    except OSError as e:
      LOGGER.warn("No local file %s" % Config.LOCAL_CHANGED_FILE)

    try:
      os.remove(LOCAL_SCORE)
    except OSError as e:
      LOGGER.warn("No local score file %s", LOCAL_SCORE)

  def set_config(self, config):
    Config.change(config)
    self.microphone.set_config()

  def set_score(self, score):
    from echomesh.util.file import File
    File.yaml_dump_all(LOCAL_SCORE, score)
    self.score.set_score(score)

def startup():
  if Config.get('autostart') or len(sys.argv) < 2 or sys.argv[1] != 'autostart':
    SetOutput.set_output(Config.get('audio', 'output', 'route'))
    return True

def shutdown():
  if Config.get('dump_unused_configs'):
    import yaml
    print(yaml.safe_dump(Config.get_unvisited()))
  Closer.on_exit()

if __name__ == '__main__':
  if startup():
    Echomesh().start()
    shutdown()
  else:
    LOGGER.info("Not autostarting because autostart=False")
<commit_msg>Tiny cleanup of Echomesh<commit_after>from __future__ import absolute_import, division, print_function, unicode_literals

import os
import sys

from echomesh.command import Score
from echomesh.config import Config
from echomesh.graphics import Display
from echomesh.network import PeerSocket
from echomesh.sound import Microphone
from echomesh.sound import SetOutput
from echomesh.util import Log
from echomesh.util.thread import Closer
from echomesh.util.thread import Keyboard

LOGGER = Log.logger(__name__)
ECHOMESH = None

class Echomesh(Closer.Closer):
  INSTANCE = None

  def __init__(self):
    super(Echomesh, self).__init__()
    if Echomesh.INSTANCE:
      LOGGER.error('There is more than one instance of Echomesh')
    else:
      Echomesh.INSTANCE = self

    self.socket = PeerSocket.PeerSocket(self)
    self.score = Score.make_score()

    self.add_openable_mutual(self.socket,
                             Keyboard.keyboard(self),
                             Display.display(self),
                             Microphone.microphone(self._mic_event),
                             self.score)

  def send(self, **data):
    self.socket.send(data)

  def receive(self, event):
    return self.score.receive_event(event)

  def start(self):
    super(Echomesh, self).start()
    self.join()

  def _mic_event(self, level):
    self.send(type='event', event='mic', key=level)

  # TODO: these next methods don't work any more.
  def remove_local(self):
    try:
      Config.remove_local()
      self.microphone.set_config()
    except OSError as e:
      LOGGER.warn("No local file %s" % Config.LOCAL_CHANGED_FILE)

    try:
      os.remove(LOCAL_SCORE)
    except OSError as e:
      LOGGER.warn("No local score file %s", LOCAL_SCORE)

  def set_config(self, config):
    Config.change(config)
    self.microphone.set_config()

  def set_score(self, score):
    from echomesh.util.file import File
    File.yaml_dump_all(LOCAL_SCORE, score)
    self.score.set_score(score)

def startup():
  if Config.get('autostart') or len(sys.argv) < 2 or sys.argv[1] != 'autostart':
    SetOutput.set_output(Config.get('audio', 'output', 'route'))
    return True

def shutdown():
  if Config.get('dump_unused_configs'):
    import yaml
    print(yaml.safe_dump(Config.get_unvisited()))
  Closer.on_exit()

if __name__ == '__main__':
  if startup():
    Echomesh().start()
    shutdown()
  else:
    LOGGER.info("Not autostarting because autostart=False")
<|endoftext|>


<commit_before>import numpy as np
import networkx as nx
import logging
from networkx.algorithms import approximation as approx
from ticket.core import TicketToRide
from ticket.board import Map

class Strategy(TicketToRide):

    def __init__(self, individual, **kwargs):
        super().__init__(**kwargs)
        self.inputs, self.input_indices = self.init_inputs()
        blank_map = Map(**kwargs)
        self.reps = nx.diameter(blank_map.map) + 1
        self.weights = [[[] for _ in range(2)] for _ in range(self.reps + 1)]
        self.player_logical_index = None
        self.prob_mutation = None
        self.individual = individual

        self.action_indices = dict(
            track=np.arange(self.NUM_EDGES),
            goals_take=self.NUM_EDGES,
            goals_threshold=self.NUM_EDGES + 1,
            goals_each=self.NUM_EDGES + 2 + np.arange(self.NUM_GOALS),
            deck=self.NUM_EDGES + self.NUM_GOALS + 2,
            faceup=self.NUM_EDGES + self.NUM_GOALS + 3 + np.arange(self.NUM_COLORS)
        )

    def set_game_turn(self, game_turn):
        self.player_logical_index = np.arange(self.players) == game_turn  # changes every game

    def init_weights(self, parent=None):

        logging.debug('building strategy for individual {}'.format(self.individual.id_))
        self.weights = [[_rand_init(self.mask[rep][ind], self.rng) for ind in range(2)] for rep in range(self.reps + 1)]

        if parent is not None:
            self.prob_mutation = self.rng.beta(self.mutation_beta_params[0], self.mutation_beta_params[1], size=(self.reps + 1, 2))
            for rep in range(self.reps + 1):
                for ind in range(2):
                    mutation_mask = self.rng.uniform(size=self.mask[rep][ind].shape) > self.prob_mutation[rep,ind]
                    self.weights[rep][ind][mutation_mask] = parent.weights[rep][ind][mutation_mask]

    def init_inputs(self):

        inputs = np.concatenate((  # non-zero values in a row R of inputs map to row R of layer 1
            np.zeros(1),  # bias
            np.zeros(1) + self.pieces_init,
            np.zeros(self.players - 1) + self.pieces_init,
            np.zeros(1),
            np.zeros(self.players - 1),
            np.zeros(self.players - 1),
            np.zeros(self.NUM_COLORS),  # faceup
            np.zeros(self.NUM_COLORS),  # hand
            np.zeros(self.NUM_GOALS),
            np.zeros(self.NUM_EDGES)
        )).astype(dtype=np.float32)

        input_indices = dict()
        input_indices['bias'] = np.array([0])
        input_indices['turn_pieces'] = next_ind(input_indices)
        input_indices['opponent_pieces'] = next_ind(input_indices) + np.arange(self.players - 1)
        input_indices['turn_points'] = next_ind(input_indices)
        input_indices['opponent_points'] = next_ind(input_indices) + np.arange(self.players - 1)
        input_indices['opponent_hand_lengths'] = next_ind(input_indices) + np.arange(self.players - 1)
        input_indices['faceups'] = next_ind(input_indices) + np.arange(self.NUM_COLORS)
        input_indices['hand_colors'] = next_ind(input_indices) + np.arange(self.NUM_COLORS)
        input_indices['goals'] = next_ind(input_indices) + np.arange(self.NUM_GOALS)
        input_indices['edges'] = next_ind(input_indices) + np.arange(self.NUM_EDGES)

        return inputs, input_indices

    def update_inputs(self, input_type, game):

        turn = game.turn

        if input_type == 'all' or input_type == 'edges':
            self.inputs[self.input_indices['turn_pieces']] = self.norm(game.pieces[self.player_logical_index], 'pieces')
            self.inputs[self.input_indices['opponent_pieces']] = self.norm(
                game.pieces[np.logical_not(self.player_logical_index)], 'pieces')
            self.inputs[self.input_indices['turn_points']] = self.norm(game.points[self.player_logical_index], 'points')
            self.inputs[self.input_indices['opponent_points']] = self.norm(
                game.points[np.logical_not(self.player_logical_index)], 'points')
            self.inputs[self.input_indices['edges']] = game.map.extract_feature(range(self.NUM_EDGES), turn=turn)

        if input_type == 'all' or input_type == 'edges' or input_type == 'goal':
            goal_points = np.zeros(self.NUM_GOALS)
            subgraph = game.map.create_player_subgraph(turn)
            for g in range(game.cards.goals['hands'][turn].shape[0]):
                ind = game.cards.goals['hands'][turn].index[g]
                frm = game.cards.goals['hands'][turn].iloc[g, 0]
                to = game.cards.goals['hands'][turn].iloc[g, 1]
                points = game.cards.goals['hands'][turn].iloc[g, 2]
                if not approx.local_node_connectivity(subgraph, frm, to):
                    points = -points
                goal_points[ind] = points
            self.inputs[self.input_indices['goals']] = self.norm(goal_points, 'goals')

        if input_type == 'all' or input_type == 'resources':
            hand_lengths = np.array([len(game.cards.resources['hands'][trn]) for trn in range(self.players)])
            self.inputs[self.input_indices['opponent_hand_lengths']] = self.norm(
                hand_lengths[np.logical_not(self.player_logical_index)], 'hand_length')
            self.inputs[self.input_indices['faceups']] = self.norm(game.cards.color_count('faceup', dtype='array'),
                                                                   'faceups')
            self.inputs[self.input_indices['hand_colors']] = self.norm(
                game.cards.color_count('hands', turn=turn, dtype='array'), 'hand')

    def feedforward(self):
        y = self.inputs
        for rep in range(self.reps + 1):
            if rep > 0:
                y = _catbias(y)
            y = np.tanh(np.matmul(y, self.weights[rep][0]))  # onto 4 superclusters (final layer: just Edges, Colors)
            y = _relu(np.matmul(_catbias(y), self.weights[rep][1]))  # onto Edges (final layer: output valuation)
        action_values = dict(
            track=list(y[self.action_indices['track']]),
            goals_take=y[self.action_indices['goals_take']],
            goals_threshold=y[self.action_indices['goals_threshold']],
            goals_each=np.array(y[self.action_indices['goals_each']]),
            deck=y[self.action_indices['deck']],
            faceup=np.array(y[self.action_indices['faceup']]),
        )

        if not isinstance(y[0], np.float32):
            raise self.Error('output is not float32')

        return action_values

    def norm(self, x, ntype):
        if ntype == 'points':
            return (x - 30) / 30
        elif ntype == 'pieces':
            return (x - 30) / 30
        elif ntype == 'goals':
            return x / 11
        elif ntype == 'faceups':
            return (x - .5) / .5
        elif ntype == 'hand':
            return (x - 3.5) / 3.5
        elif ntype == 'hand_length':
            return (x - 10) / 10
        elif ntype == 'distance':
            return (x - 3.5) / 3.5
        else:
            raise self.Error('invalid normalization type {}'.format(ntype))

    # end class Strategy

def next_ind(x):
    return np.max(np.concatenate((list(x.values()))), keepdims=True) + 1

def _catbias(x):
    return np.concatenate((np.ones(1, dtype=np.float32), x))

def _rand_init(m, rng):
    norms = m.sum(axis=1, dtype=np.int16)
    w = np.zeros(m.shape, dtype=np.float32)
    w[m] = rng.uniform(-.5, .5, size=norms.sum()).astype(np.float32)
    return (w.T / np.sqrt(norms)).T

def _relu(x):
    return np.maximum(x, 0)

def _lincomb(x, y, p):
    return p * x + (1 - p) * y
<commit_msg>Initializing weights normalization fix<commit_after>import numpy as np
import networkx as nx
import logging
from networkx.algorithms import approximation as approx
from ticket.core import TicketToRide
from ticket.board import Map

class Strategy(TicketToRide):

    def __init__(self, individual, **kwargs):
        super().__init__(**kwargs)
        self.inputs, self.input_indices = self.init_inputs()
        blank_map = Map(**kwargs)
        self.reps = nx.diameter(blank_map.map) + 1
        self.weights = [[[] for _ in range(2)] for _ in range(self.reps + 1)]
        self.player_logical_index = None
        self.prob_mutation = None
        self.individual = individual

        self.action_indices = dict(
            track=np.arange(self.NUM_EDGES),
            goals_take=self.NUM_EDGES,
            goals_threshold=self.NUM_EDGES + 1,
            goals_each=self.NUM_EDGES + 2 + np.arange(self.NUM_GOALS),
            deck=self.NUM_EDGES + self.NUM_GOALS + 2,
            faceup=self.NUM_EDGES + self.NUM_GOALS + 3 + np.arange(self.NUM_COLORS)
        )

    def set_game_turn(self, game_turn):
        self.player_logical_index = np.arange(self.players) == game_turn  # changes every game

    def init_weights(self, parent=None):

        logging.debug('building strategy for individual {}'.format(self.individual.id_))
        self.weights = [[_rand_init(self.mask[rep][ind], self.rng) for ind in range(2)] for rep in range(self.reps + 1)]

        if parent is not None:
            self.prob_mutation = self.rng.beta(self.mutation_beta_params[0], self.mutation_beta_params[1],
                                               size=(self.reps + 1, 2))
            for rep in range(self.reps + 1):
                for ind in range(2):
                    mutation_mask = self.rng.uniform(size=self.mask[rep][ind].shape) > self.prob_mutation[rep, ind]
                    self.weights[rep][ind][mutation_mask] = parent.weights[rep][ind][mutation_mask]

    def init_inputs(self):

        inputs = np.concatenate((  # non-zero values in a row R of inputs map to row R of layer 1
            np.zeros(1),  # bias
            np.zeros(1) + self.pieces_init,
            np.zeros(self.players - 1) + self.pieces_init,
            np.zeros(1),
            np.zeros(self.players - 1),
            np.zeros(self.players - 1),
            np.zeros(self.NUM_COLORS),  # faceup
            np.zeros(self.NUM_COLORS),  # hand
            np.zeros(self.NUM_GOALS),
            np.zeros(self.NUM_EDGES)
        )).astype(dtype=np.float32)

        input_indices = dict()
        input_indices['bias'] = np.array([0])
        input_indices['turn_pieces'] = next_ind(input_indices)
        input_indices['opponent_pieces'] = next_ind(input_indices) + np.arange(self.players - 1)
        input_indices['turn_points'] = next_ind(input_indices)
        input_indices['opponent_points'] = next_ind(input_indices) + np.arange(self.players - 1)
        input_indices['opponent_hand_lengths'] = next_ind(input_indices) + np.arange(self.players - 1)
        input_indices['faceups'] = next_ind(input_indices) + np.arange(self.NUM_COLORS)
        input_indices['hand_colors'] = next_ind(input_indices) + np.arange(self.NUM_COLORS)
        input_indices['goals'] = next_ind(input_indices) + np.arange(self.NUM_GOALS)
        input_indices['edges'] = next_ind(input_indices) + np.arange(self.NUM_EDGES)

        return inputs, input_indices

    def update_inputs(self, input_type, game):

        turn = game.turn

        if input_type == 'all' or input_type == 'edges':
            self.inputs[self.input_indices['turn_pieces']] = self.norm(game.pieces[self.player_logical_index], 'pieces')
            self.inputs[self.input_indices['opponent_pieces']] = self.norm(
                game.pieces[np.logical_not(self.player_logical_index)], 'pieces')
            self.inputs[self.input_indices['turn_points']] = self.norm(game.points[self.player_logical_index], 'points')
            self.inputs[self.input_indices['opponent_points']] = self.norm(
                game.points[np.logical_not(self.player_logical_index)], 'points')
            self.inputs[self.input_indices['edges']] = game.map.extract_feature(range(self.NUM_EDGES), turn=turn)

        if input_type == 'all' or input_type == 'edges' or input_type == 'goal':
            goal_points = np.zeros(self.NUM_GOALS)
            subgraph = game.map.create_player_subgraph(turn)
            for g in range(game.cards.goals['hands'][turn].shape[0]):
                ind = game.cards.goals['hands'][turn].index[g]
                frm = game.cards.goals['hands'][turn].iloc[g, 0]
                to = game.cards.goals['hands'][turn].iloc[g, 1]
                points = game.cards.goals['hands'][turn].iloc[g, 2]
                if not approx.local_node_connectivity(subgraph, frm, to):
                    points = -points
                goal_points[ind] = points
            self.inputs[self.input_indices['goals']] = self.norm(goal_points, 'goals')

        if input_type == 'all' or input_type == 'resources':
            hand_lengths = np.array([len(game.cards.resources['hands'][trn]) for trn in range(self.players)])
            self.inputs[self.input_indices['opponent_hand_lengths']] = self.norm(
                hand_lengths[np.logical_not(self.player_logical_index)], 'hand_length')
            self.inputs[self.input_indices['faceups']] = self.norm(game.cards.color_count('faceup', dtype='array'),
                                                                   'faceups')
            self.inputs[self.input_indices['hand_colors']] = self.norm(
                game.cards.color_count('hands', turn=turn, dtype='array'), 'hand')

    def feedforward(self):
        y = self.inputs
        for rep in range(self.reps + 1):
            if rep > 0:
                y = _catbias(y)
            y = np.tanh(np.matmul(y, self.weights[rep][0]))  # onto 4 superclusters (final layer: just Edges, Colors)
            y = _relu(np.matmul(_catbias(y), self.weights[rep][1]))  # onto Edges (final layer: output valuation)
        action_values = dict(
            track=list(y[self.action_indices['track']]),
            goals_take=y[self.action_indices['goals_take']],
            goals_threshold=y[self.action_indices['goals_threshold']],
            goals_each=np.array(y[self.action_indices['goals_each']]),
            deck=y[self.action_indices['deck']],
            faceup=np.array(y[self.action_indices['faceup']]),
        )

        if not isinstance(y[0], np.float32):
            raise self.Error('output is not float32')

        return action_values

    def norm(self, x, ntype):
        if ntype == 'points':
            return (x - 30) / 30
        elif ntype == 'pieces':
            return (x - 30) / 30
        elif ntype == 'goals':
            return x / 11
        elif ntype == 'faceups':
            return (x - .5) / .5
        elif ntype == 'hand':
            return (x - 3.5) / 3.5
        elif ntype == 'hand_length':
            return (x - 10) / 10
        elif ntype == 'distance':
            return (x - 3.5) / 3.5
        else:
            raise self.Error('invalid normalization type {}'.format(ntype))

    # end class Strategy

def next_ind(x):
    return np.max(np.concatenate((list(x.values()))), keepdims=True) + 1

def _catbias(x):
    return np.concatenate((np.ones(1, dtype=np.float32), x))

def _rand_init(m, rng):
    norms = m.sum(axis=0, dtype=np.int16)
    w = np.zeros(m.shape, dtype=np.float32)
    w[m] = rng.uniform(-.5, .5, size=norms.sum()).astype(np.float32)
    return w / np.sqrt(norms)

def _relu(x):
    return np.maximum(x, 0)

<|endoftext|>