<commit_before>import json
import pytz
import redis
from itertools import groupby

from django.contrib import messages
from django.conf import settings
from django.core.exceptions import PermissionDenied
from django.core.urlresolvers import reverse
from django.http import Http404, HttpResponse
from django.shortcuts import redirect
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _, ugettext as __
from django.views import generic

from rq import Queue, Worker, get_failed_queue, push_connection
from rq.exceptions import NoSuchJobError
from rq.job import Job

try:
    from rq_scheduler import Scheduler
except ImportError:
    # rq_scheduler is not installed
    Scheduler = None

from .forms import QueueForm, JobForm

utc = pytz.timezone('UTC')

def serialize_job(job):
    return dict(
        id=job.id,
        key=job.key,
        created_at=timezone.make_aware(job.created_at, utc),
        enqueued_at=timezone.make_aware(job.enqueued_at,
                                        utc) if job.enqueued_at else None,
        ended_at=timezone.make_aware(job.ended_at,
                                     utc) if job.ended_at else None,
        origin=job.origin,
        result=job.result,
        exc_info=job.exc_info,
        description=job.description,
    )

def serialize_queue(queue):
    return dict(
        name=queue.name,
        count=queue.count,
        url=reverse('rq_queue', args=[queue.name]),
    )

def serialize_worker(worker):
    return dict(
        name=worker.name,
        queues=[q.name for q in worker.queues],
        state=worker.get_state().decode('utf-8'),
        url=reverse('rq_worker', args=[worker.name]),
    )

def serialize_scheduled_job(job, next_run):
    adict = serialize_job(job)
    adict['repeat'] = job.meta.get('repeat', None)
    adict['interval'] = job.meta.get('interval', None)
    adict['next_run'] = next_run
    return adict

def serialize_scheduled_queues(queue):
    return dict(
        url=reverse('rq_scheduler', args=[queue['name']]),
        **queue)

class SuperUserMixin(object):
    def dispatch(self, request, *args, **kwargs):
        if not request.user.is_superuser:
            raise PermissionDenied

        opts = getattr(settings, 'RQ', {}).copy()
        opts.pop('eager', None)
        self.connection = redis.Redis(**opts)
        push_connection(self.connection)

        return super(SuperUserMixin, self).dispatch(request, *args, **kwargs)

class Stats(SuperUserMixin, generic.TemplateView):
    template_name = 'rq/stats.html'

    def get_context_data(self, **kwargs):
        ctx = super(Stats, self).get_context_data(**kwargs)
        ctx.update({
            'queues': Queue.all(connection=self.connection),
            'workers': Worker.all(connection=self.connection),
            'has_permission': True,
            'title': 'RQ Status',
        })
        if Scheduler:
            scheduler = Scheduler(self.connection)
            get_queue = lambda job: job.origin
            all_jobs = sorted(scheduler.get_jobs(), key=get_queue)
            ctx['scheduler'] = scheduler
            ctx['scheduled_queues'] = [
                {'name': queue, 'job_count': len(list(jobs))}
                for queue, jobs in groupby(all_jobs, get_queue)]
        return ctx

    def render_to_response(self, context, **response_kwargs):
        if self.request.is_ajax():
            data = json.dumps({
                'queues': [serialize_queue(q) for q in context['queues']],
                'workers': [serialize_worker(w) for w in context['workers']],
                'scheduled_queues': [serialize_scheduled_queues(q)
                                     for q in context.get('scheduled_queues', [])],
            })
            return HttpResponse(
                data, content_type='application/json; charset=UTF-8',
            )
        return super(Stats, self).render_to_response(context,
                                                     **response_kwargs)
stats = Stats.as_view()

class QueueDetails(SuperUserMixin, generic.FormView):
    template_name = 'rq/queue.html'
    form_class = QueueForm

    def get_success_url(self):
        return reverse('rq_queue', kwargs=self.kwargs)

    def get_context_data(self, **kwargs):
        ctx = super(QueueDetails, self).get_context_data(**kwargs)
        queue = Queue(self.kwargs['queue'], connection=self.connection)
        ctx.update({
            'queue': queue,
            'jobs': [serialize_job(job) for job in queue.jobs],
            'has_permission': True,
            'title': "'%s' queue" % queue.name,
            'failed': queue.name == 'failed',
        })
        return ctx

    def get_form_kwargs(self):
        kwargs = super(QueueDetails, self).get_form_kwargs()
        kwargs['queue'] = Queue(self.kwargs['queue'],
                                connection=self.connection)
        return kwargs

    def form_valid(self, form):
        form.save()
        msgs = {
            'compact': __('Queue compacted'),
            'empty': __('Queue emptied'),
            'requeue': __('Jobs requeued'),
        }
        messages.success(self.request, msgs[form.cleaned_data])
        return super(QueueDetails, self).form_valid(form)
queue = QueueDetails.as_view()

class JobDetails(SuperUserMixin, generic.FormView):
    template_name = 'rq/job.html'
    form_class = JobForm

    def get_form_kwargs(self):
        kwargs = super(JobDetails, self).get_form_kwargs()
        self.job = Job.fetch(self.kwargs['job'], connection=self.connection)
        kwargs['job'] = self.job
        return kwargs

    def get_context_data(self, **kwargs):
        ctx = super(JobDetails, self).get_context_data(**kwargs)
        try:
            job = Job.fetch(self.kwargs['job'], connection=self.connection)
        except NoSuchJobError:
            raise Http404
        if job.is_failed:
            queue = get_failed_queue(connection=self.connection)
        else:
            queue = Queue(job.origin, connection=self.connection)
        ctx.update({
            'job': serialize_job(job),
            'queue': queue,
            'has_permission': True,
            'title': _('Job %s') % job.id,
        })
        return ctx

    def form_valid(self, form):
        queue = 'failed' if form.job.is_failed else form.job.origin
        form.save()
        msgs = {
            'requeue': __('Job requeued'),
            'cancel': __('Job canceled'),
        }
        messages.success(self.request, msgs[form.cleaned_data])
        return redirect(reverse('rq_queue', args=[queue]))
job = JobDetails.as_view()

class WorkerDetails(SuperUserMixin, generic.TemplateView):
    template_name = 'rq/worker.html'

    def get_context_data(self, **kwargs):
        ctx = super(WorkerDetails, self).get_context_data(**kwargs)
        key = Worker.redis_worker_namespace_prefix + self.kwargs['worker']
        worker = Worker.find_by_key(key, connection=self.connection)
        ctx.update({
            'worker': worker,
            'has_permission': True,
            'title': _('Worker %s') % worker.name,
        })
        return ctx
worker = WorkerDetails.as_view()

class SchedulerDetails(SuperUserMixin, generic.TemplateView):
    template_name = 'rq/scheduler.html'

    def get_context_data(self, **kwargs):
        ctx = super(SchedulerDetails, self).get_context_data(**kwargs)
        if Scheduler is None:
            # rq_scheduler is not installed
            raise Http404
        scheduler = Scheduler(self.connection)
        queue = Queue(self.kwargs['queue'], connection=self.connection)

        def cond(job, next_run):
            return job.origin == queue.name
        jobs = filter(cond, scheduler.get_jobs(with_times=True))

        ctx.update({
            'queue': queue,
            'jobs': [serialize_scheduled_job(job, next_run)
                     for job, next_run in jobs],
            'has_permission': True,
            'title': "Jobs scheduled on '%s' queue" % queue.name,
        })
        return ctx

scheduler = SchedulerDetails.as_view()
<commit_msg>properly unpack filter arg<commit_after>import json
import pytz
import redis
from itertools import groupby

from django.contrib import messages
from django.conf import settings
from django.core.exceptions import PermissionDenied
from django.core.urlresolvers import reverse
from django.http import Http404, HttpResponse
from django.shortcuts import redirect
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _, ugettext as __
from django.views import generic

from rq import Queue, Worker, get_failed_queue, push_connection
from rq.exceptions import NoSuchJobError
from rq.job import Job

try:
    from rq_scheduler import Scheduler
except ImportError:
    # rq_scheduler is not installed
    Scheduler = None

from .forms import QueueForm, JobForm

utc = pytz.timezone('UTC')

def serialize_job(job):
    return dict(
        id=job.id,
        key=job.key,
        created_at=timezone.make_aware(job.created_at, utc),
        enqueued_at=timezone.make_aware(job.enqueued_at,
                                        utc) if job.enqueued_at else None,
        ended_at=timezone.make_aware(job.ended_at,
                                     utc) if job.ended_at else None,
        origin=job.origin,
        result=job.result,
        exc_info=job.exc_info,
        description=job.description,
    )

def serialize_queue(queue):
    return dict(
        name=queue.name,
        count=queue.count,
        url=reverse('rq_queue', args=[queue.name]),
    )

def serialize_worker(worker):
    return dict(
        name=worker.name,
        queues=[q.name for q in worker.queues],
        state=worker.get_state().decode('utf-8'),
        url=reverse('rq_worker', args=[worker.name]),
    )

def serialize_scheduled_job(job, next_run):
    adict = serialize_job(job)
    adict['repeat'] = job.meta.get('repeat', None)
    adict['interval'] = job.meta.get('interval', None)
    adict['next_run'] = next_run
    return adict

def serialize_scheduled_queues(queue):
    return dict(
        url=reverse('rq_scheduler', args=[queue['name']]),
        **queue)

class SuperUserMixin(object):
    def dispatch(self, request, *args, **kwargs):
        if not request.user.is_superuser:
            raise PermissionDenied

        opts = getattr(settings, 'RQ', {}).copy()
        opts.pop('eager', None)
        self.connection = redis.Redis(**opts)
        push_connection(self.connection)

        return super(SuperUserMixin, self).dispatch(request, *args, **kwargs)

class Stats(SuperUserMixin, generic.TemplateView):
    template_name = 'rq/stats.html'

    def get_context_data(self, **kwargs):
        ctx = super(Stats, self).get_context_data(**kwargs)
        ctx.update({
            'queues': Queue.all(connection=self.connection),
            'workers': Worker.all(connection=self.connection),
            'has_permission': True,
            'title': 'RQ Status',
        })
        if Scheduler:
            scheduler = Scheduler(self.connection)
            get_queue = lambda job: job.origin
            all_jobs = sorted(scheduler.get_jobs(), key=get_queue)
            ctx['scheduler'] = scheduler
            ctx['scheduled_queues'] = [
                {'name': queue, 'job_count': len(list(jobs))}
                for queue, jobs in groupby(all_jobs, get_queue)]
        return ctx

    def render_to_response(self, context, **response_kwargs):
        if self.request.is_ajax():
            data = json.dumps({
                'queues': [serialize_queue(q) for q in context['queues']],
                'workers': [serialize_worker(w) for w in context['workers']],
                'scheduled_queues': [serialize_scheduled_queues(q)
                                     for q in context.get('scheduled_queues', [])],
            })
            return HttpResponse(
                data, content_type='application/json; charset=UTF-8',
            )
        return super(Stats, self).render_to_response(context,
                                                     **response_kwargs)
stats = Stats.as_view()

class QueueDetails(SuperUserMixin, generic.FormView):
    template_name = 'rq/queue.html'
    form_class = QueueForm

    def get_success_url(self):
        return reverse('rq_queue', kwargs=self.kwargs)

    def get_context_data(self, **kwargs):
        ctx = super(QueueDetails, self).get_context_data(**kwargs)
        queue = Queue(self.kwargs['queue'], connection=self.connection)
        ctx.update({
            'queue': queue,
            'jobs': [serialize_job(job) for job in queue.jobs],
            'has_permission': True,
            'title': "'%s' queue" % queue.name,
            'failed': queue.name == 'failed',
        })
        return ctx

    def get_form_kwargs(self):
        kwargs = super(QueueDetails, self).get_form_kwargs()
        kwargs['queue'] = Queue(self.kwargs['queue'],
                                connection=self.connection)
        return kwargs

    def form_valid(self, form):
        form.save()
        msgs = {
            'compact': __('Queue compacted'),
            'empty': __('Queue emptied'),
            'requeue': __('Jobs requeued'),
        }
        messages.success(self.request, msgs[form.cleaned_data])
        return super(QueueDetails, self).form_valid(form)
queue = QueueDetails.as_view()

class JobDetails(SuperUserMixin, generic.FormView):
    template_name = 'rq/job.html'
    form_class = JobForm

    def get_form_kwargs(self):
        kwargs = super(JobDetails, self).get_form_kwargs()
        self.job = Job.fetch(self.kwargs['job'], connection=self.connection)
        kwargs['job'] = self.job
        return kwargs

    def get_context_data(self, **kwargs):
        ctx = super(JobDetails, self).get_context_data(**kwargs)
        try:
            job = Job.fetch(self.kwargs['job'], connection=self.connection)
        except NoSuchJobError:
            raise Http404
        if job.is_failed:
            queue = get_failed_queue(connection=self.connection)
        else:
            queue = Queue(job.origin, connection=self.connection)
        ctx.update({
            'job': serialize_job(job),
            'queue': queue,
            'has_permission': True,
            'title': _('Job %s') % job.id,
        })
        return ctx

    def form_valid(self, form):
        queue = 'failed' if form.job.is_failed else form.job.origin
        form.save()
        msgs = {
            'requeue': __('Job requeued'),
            'cancel': __('Job canceled'),
        }
        messages.success(self.request, msgs[form.cleaned_data])
        return redirect(reverse('rq_queue', args=[queue]))
job = JobDetails.as_view()

class WorkerDetails(SuperUserMixin, generic.TemplateView):
    template_name = 'rq/worker.html'

    def get_context_data(self, **kwargs):
        ctx = super(WorkerDetails, self).get_context_data(**kwargs)
        key = Worker.redis_worker_namespace_prefix + self.kwargs['worker']
        worker = Worker.find_by_key(key, connection=self.connection)
        ctx.update({
            'worker': worker,
            'has_permission': True,
            'title': _('Worker %s') % worker.name,
        })
        return ctx
worker = WorkerDetails.as_view()

class SchedulerDetails(SuperUserMixin, generic.TemplateView):
    template_name = 'rq/scheduler.html'

    def get_context_data(self, **kwargs):
        ctx = super(SchedulerDetails, self).get_context_data(**kwargs)
        if Scheduler is None:
            # rq_scheduler is not installed
            raise Http404
        scheduler = Scheduler(self.connection)
        queue = Queue(self.kwargs['queue'], connection=self.connection)

        def cond(job_tuple):
            job, next_run = job_tuple
            return job.origin == queue.name
        jobs = filter(cond, scheduler.get_jobs(with_times=True))

        ctx.update({
            'queue': queue,
            'jobs': [serialize_scheduled_job(job, next_run)
                     for job, next_run in jobs],
            'has_permission': True,
            'title': "Jobs scheduled on '%s' queue" % queue.name,
        })
        return ctx

scheduler = SchedulerDetails.as_view()
<|endoftext|>


<commit_before># Copyright (c) 2013, Universal Resource Trading Limited and contributors
# For license information, please see license.txt

import json
import math
import sys
import os.path
from collections.abc import Sequence

import frappe

from erpnext_ebay.ebay_revise_requests import (
    revise_inventory_status, relist_item, end_items)

from ebaysdk.exception import ConnectionError
from ebaysdk.trading import Connection as Trading

class eBayPartialFailure(frappe.ValidationError):
    pass

def chunker(seq, size):
    """Collect data into fixed-length chunks. From answer by nosklo in
    https://stackoverflow.com/questions/434287/
    """
    return (seq[pos:pos + size] for pos in range(0, len(seq), size))

def revise_ebay_prices(price_data, print=print):
    """Revises multiple eBay prices. Attempts to pack price updates into as few
    ReviseInventoryStatus calls as possible.
    Accepts a list of tuples, each of which contains:
      - ebay_id
      - new_price
      - optional extra values
    """

    if len(price_data) == 0:
        print('No prices to update!')
        return

    item_data = [
        (ebay_id, new_price, None)
        for (ebay_id, new_price, *_) in price_data
    ]

    revise_ebay_inventory(item_data, print=print)

def revise_ebay_quantities(qty_data, print=print):
    """Revises multiple eBay quantities. Attempts to pack quantity updates
    into as few ReviseInventoryStatus calls as possible.
    Accepts a list of tuples, each of which contains:
      - ebay_id
      - new_qty
      - optional extra values
    """

    if len(qty_data) == 0:
        print('No quantities to update!')
        return

    revise_listings = []
    end_listings = []
    for ebay_id, new_qty, *_ in qty_data:
        if new_qty == 0:
            end_listings.append((ebay_id, 'NotAvailable'))
        else:
            revise_listings.append((ebay_id, None, new_qty))

    # First revise listing quantities
    if revise_listings:
        revise_ebay_inventory(revise_listings, print=print)

    # Then end listings
    if end_listings:
        end_ebay_listings(end_listings, print=print)

def revise_ebay_inventory(item_data, print=print):
    """Revises multiple eBay prices and quantities. Attempts to pack
    price updates into as few ReviseInventoryStatus calls as possible.
    Accepts a list of tuples of the form (ebay_id, price, qty).
    If either price or qty is None, the price or qty, respectively,
    is not changed.
    """

    CHUNK_SIZE = 4

    items = []
    for ebay_id, price, qty in item_data:
        if price is None and qty is None:
            continue
        item_dict = {'ItemID': ebay_id}
        if price is not None:
            item_dict['StartPrice'] = price
        if qty is not None:
            item_dict['Quantity'] = qty
        items.append(item_dict)

    prev_percent = -1000.0
    n_items = len(items)
    n_chunks = ((n_items - 1) // CHUNK_SIZE) + 1  # Number of chunks of 4 items
    print('n_chunks: ', n_chunks)

    if n_items == 0:
        print('No items to update!')
        return

    for i, chunked_items in enumerate(chunker(items, CHUNK_SIZE)):
        percent = math.floor(100.0 * i / n_chunks)
        if percent - prev_percent > 9.9:
            print(f' - {int(percent)}% complete...')
        prev_percent = percent

        # Submit the updates for these items.
        revise_inventory_status(chunked_items)

    print(' - 100% complete.')

@frappe.whitelist()
def client_revise_ebay_item(item_data):
    """Revise an item's price and/or qty from the JS front-end.
    Will end a listing if the qty is set to zero.
    """

    # Whitelisted function; check permissions
    if not frappe.has_permission('eBay Manager', 'write'):
        frappe.throw('Need write permissions on eBay Manager!',
                     frappe.PermissionError)

    item_data = json.loads(item_data)
    qty = item_data.get('qty')
    if qty == 0:
        item = (item_data['ebay_id'], 'NotAvailable')
        end_ebay_listings([item])
    else:
        item = item_data['ebay_id'], item_data.get('price'), qty
        revise_ebay_inventory([item])

def relist_ebay_item(ebay_id, item_dict=None):
    """Relist an eBay listing."""

    relist_item(ebay_id, item_dict=item_dict)

@frappe.whitelist()
def client_relist_ebay_item(ebay_id, item_dict=None):
    """Relist a fixed-price eBay list from the JS front-end."""

    # Whitelisted function; check permissions
    if not frappe.has_permission('eBay Manager', 'write'):
        frappe.throw('Need write permissions on eBay Manager!',
                     frappe.PermissionError)

    if isinstance(item_dict, str):
        item_dict = json.loads(item_dict)

    if not isinstance(item_dict, dict):
        frappe.throw('Invalid format for item_dict!')

    relist_item(ebay_id, item_dict=item_dict)

def end_ebay_listings(listings, print=print):
    """Ends a number of eBay listings.

    Arguments:
      - listings: a sequence of (ItemID, EndingReason) tuples.

    EndingReasons can be:
      - Incorrect (start price or reserve price is incorrect)
      - LostOrBroken (item is lost or broken)
      - NotAvailable (item is no longer available for sale)
      - OtherListingError (error other than the start or reserve price)
      - SellToHighBidder (only for Auctions)
    """

    CHUNK_SIZE = 10

    items = [
        {'ItemID': ebay_id, 'EndingReason': reason}
        for ebay_id, reason in listings
    ]

    prev_percent = -1000.0
    n_items = len(items)
    n_chunks = ((n_items - 1) // CHUNK_SIZE) + 1  # Number of chunks of items
    print('n_chunks: ', n_chunks)

    if n_items == 0:
        print('No listings to end!')
        return

    for i, chunked_items in enumerate(chunker(items, CHUNK_SIZE)):
        percent = math.floor(100.0 * i / n_chunks)
        if percent - prev_percent > 9.9:
            print(f' - {int(percent)}% complete...')
        prev_percent = percent

        # Submit the updates for these items.
        response = end_items(chunked_items)
        print(response)

        print('response[Ack] = ', response['Ack'])
        if response['Ack'] != 'Success':
            print('response not success')
            messages = []
            response_items = response['EndItemResponseContainer']
            if not isinstance(response_items, Sequence):
                response_items = [response_items]
            for item in response_items:
                if 'Errors' not in item:
                    continue
                elif isinstance(item['Errors'], Sequence):
                    errors = item['Errors']
                else:
                    errors = [item['Errors']]
                messages = []
                for e in errors:
                    messages.append(
                        f'{e["SeverityCode"]} code {e["ErrorCode"]} (Item ID '
                        + f'{item["CorrelationID"]}): {e["LongMessage"]}'
                    )
            frappe.throw('\n'.join(messages),
                         exc=eBayPartialFailure)

    print(' - 100% complete.')

@frappe.whitelist()
def client_end_ebay_listings(ebay_ids):
    """End listings from the JS front-end."""

    if isinstance(ebay_ids, str):
        ebay_ids = json.loads(ebay_ids)
    if not isinstance(ebay_ids, list):
        frappe.throw('Invalid ebay_ids format!')

    listings = [(x, 'NotAvailable') for x in ebay_ids]

    end_ebay_listings(listings)
<commit_msg>fix(revise): Add better handling to price revision etc.<commit_after># Copyright (c) 2013, Universal Resource Trading Limited and contributors
# For license information, please see license.txt

import json
import math
import sys
import os.path
from collections.abc import Sequence

import frappe

from erpnext_ebay.ebay_revise_requests import (
    revise_inventory_status, relist_item, end_items)

from ebaysdk.exception import ConnectionError
from ebaysdk.trading import Connection as Trading

class eBayPartialFailure(frappe.ValidationError):
    pass

def chunker(seq, size):
    """Collect data into fixed-length chunks. From answer by nosklo in
    https://stackoverflow.com/questions/434287/
    """
    return (seq[pos:pos + size] for pos in range(0, len(seq), size))

def revise_ebay_prices(price_data, print=print, **kwargs):
    """Revises multiple eBay prices. Attempts to pack price updates into as few
    ReviseInventoryStatus calls as possible.
    Accepts a list of tuples, each of which contains:
      - ebay_id
      - new_price
      - optional extra values
    """

    if len(price_data) == 0:
        print('No prices to update!')
        return

    item_data = [
        (ebay_id, new_price, None)
        for (ebay_id, new_price, *_) in price_data
    ]

    revise_ebay_inventory(item_data, print=print, **kwargs)

def revise_ebay_quantities(qty_data, print=print, **kwargs):
    """Revises multiple eBay quantities. Attempts to pack quantity updates
    into as few ReviseInventoryStatus calls as possible.
    Accepts a list of tuples, each of which contains:
      - ebay_id
      - new_qty
      - optional extra values
    """

    if len(qty_data) == 0:
        print('No quantities to update!')
        return

    revise_listings = []
    end_listings = []
    for ebay_id, new_qty, *_ in qty_data:
        if new_qty == 0:
            end_listings.append((ebay_id, 'NotAvailable'))
        else:
            revise_listings.append((ebay_id, None, new_qty))

    # First revise listing quantities
    if revise_listings:
        revise_ebay_inventory(revise_listings, print=print, **kwargs)

    # Then end listings
    if end_listings:
        end_ebay_listings(end_listings, print=print, **kwargs)

def revise_ebay_inventory(item_data, print=print, error_log=None,
                          retries=1, **kwargs):
    """Revises multiple eBay prices and quantities. Attempts to pack
    price updates into as few ReviseInventoryStatus calls as possible.
    Accepts a list of tuples of the form (ebay_id, price, qty).
    If either price or qty is None, the price or qty, respectively,
    is not changed.
    Tries each transaction 'retries' times.
    If error_log is supplied, then the process continues on error,
    appending to the error_log.
    """

    CHUNK_SIZE = 4

    items = []
    for ebay_id, price, qty in item_data:
        if price is None and qty is None:
            continue
        item_dict = {'ItemID': ebay_id}
        if price is not None:
            item_dict['StartPrice'] = price
        if qty is not None:
            item_dict['Quantity'] = qty
        items.append(item_dict)

    prev_percent = -1000.0
    n_items = len(items)
    n_chunks = ((n_items - 1) // CHUNK_SIZE) + 1  # Number of chunks of 4 items
    print('n_chunks: ', n_chunks)

    if n_items == 0:
        print('No items to update!')
        return

    for i, chunked_items in enumerate(chunker(items, CHUNK_SIZE)):
        percent = math.floor(100.0 * i / n_chunks)
        if percent - prev_percent > 9.9:
            print(f' - {int(percent)}% complete...')
        prev_percent = percent

        # Submit the updates for these items.
        for i in range(retries):
            try:
                revise_inventory_status(chunked_items)
            except Exception as e:
                error_log.append('revise_ebay_inventory exception: {e}')
            else:
                # Success
                break
            print('Retrying transaction...')
        else:
            if error_log:
                # Carry on
                error_log.append(
                    f'revise_ebay_inventory failed after {retries} retries')
            else:
                # Give up here
                raise

    print(' - 100% complete.')

@frappe.whitelist()
def client_revise_ebay_item(item_data):
    """Revise an item's price and/or qty from the JS front-end.
    Will end a listing if the qty is set to zero.
    """

    # Whitelisted function; check permissions
    if not frappe.has_permission('eBay Manager', 'write'):
        frappe.throw('Need write permissions on eBay Manager!',
                     frappe.PermissionError)

    item_data = json.loads(item_data)
    qty = item_data.get('qty')
    if qty == 0:
        item = (item_data['ebay_id'], 'NotAvailable')
        end_ebay_listings([item])
    else:
        item = item_data['ebay_id'], item_data.get('price'), qty
        revise_ebay_inventory([item])

def relist_ebay_item(ebay_id, item_dict=None):
    """Relist an eBay listing."""

    relist_item(ebay_id, item_dict=item_dict)

@frappe.whitelist()
def client_relist_ebay_item(ebay_id, item_dict=None):
    """Relist a fixed-price eBay list from the JS front-end."""

    # Whitelisted function; check permissions
    if not frappe.has_permission('eBay Manager', 'write'):
        frappe.throw('Need write permissions on eBay Manager!',
                     frappe.PermissionError)

    if isinstance(item_dict, str):
        item_dict = json.loads(item_dict)

    if not isinstance(item_dict, dict):
        frappe.throw('Invalid format for item_dict!')

    relist_item(ebay_id, item_dict=item_dict)

def end_ebay_listings(listings, print=print, **kwargs):
    """Ends a number of eBay listings.

    Arguments:
      - listings: a sequence of (ItemID, EndingReason) tuples.

    EndingReasons can be:
      - Incorrect (start price or reserve price is incorrect)
      - LostOrBroken (item is lost or broken)
      - NotAvailable (item is no longer available for sale)
      - OtherListingError (error other than the start or reserve price)
      - SellToHighBidder (only for Auctions)
    """

    CHUNK_SIZE = 10

    items = [
        {'ItemID': ebay_id, 'EndingReason': reason}
        for ebay_id, reason in listings
    ]

    prev_percent = -1000.0
    n_items = len(items)
    n_chunks = ((n_items - 1) // CHUNK_SIZE) + 1  # Number of chunks of items
    print('n_chunks: ', n_chunks)

    if n_items == 0:
        print('No listings to end!')
        return

    for i, chunked_items in enumerate(chunker(items, CHUNK_SIZE)):
        percent = math.floor(100.0 * i / n_chunks)
        if percent - prev_percent > 9.9:
            print(f' - {int(percent)}% complete...')
        prev_percent = percent

        # Submit the updates for these items.
        response = end_items(chunked_items)
        print(response)

        print('response[Ack] = ', response['Ack'])
        if response['Ack'] != 'Success':
            print('response not success')
            messages = []
            response_items = response['EndItemResponseContainer']
            if not isinstance(response_items, Sequence):
                response_items = [response_items]
            for item in response_items:
                if 'Errors' not in item:
                    continue
                elif isinstance(item['Errors'], Sequence):
                    errors = item['Errors']
                else:
                    errors = [item['Errors']]
                messages = []
                for e in errors:
                    messages.append(
                        f'{e["SeverityCode"]} code {e["ErrorCode"]} (Item ID '
                        + f'{item["CorrelationID"]}): {e["LongMessage"]}'
                    )
            frappe.throw('\n'.join(messages),
                         exc=eBayPartialFailure)

    print(' - 100% complete.')

@frappe.whitelist()
def client_end_ebay_listings(ebay_ids):
    """End listings from the JS front-end."""

    if isinstance(ebay_ids, str):
        ebay_ids = json.loads(ebay_ids)
    if not isinstance(ebay_ids, list):
        frappe.throw('Invalid ebay_ids format!')

    listings = [(x, 'NotAvailable') for x in ebay_ids]

    end_ebay_listings(listings)
<|endoftext|>


<commit_before>#!/usr/bin/python3
#-*-coding:utf-8-*-
#$File: model.py
#$Date: Sat May  7 10:59:45 2016
#$Author: Like Ma <milkpku[at]gmail[dot]com>

from config import config

import tensorflow as tf
import functools

from util.model import Model, conv2d

def get_model(name):
    with tf.name_scope(name) as scope:

        self_pos = tf.placeholder(config.dtype, config.data_shape, name='self_pos')
        enemy_pos = tf.placeholder(config.dtype, config.data_shape, name='enemy_pos')
        self_ability = tf.placeholder(config.dtype, config.data_shape, name='self_ability')
        enemy_ability = tf.placeholder(config.dtype, config.data_shape, name='enemy_ability')
        self_protect = tf.placeholder(config.dtype, config.data_shape, name='self_protect')
        enemy_protect = tf.placeholder(config.dtype, config.data_shape, name='enemy_protect')

        input_label = tf.placeholder(config.dtype, config.label_shape, name='input_label')

        x = tf.concat(3, [self_pos, enemy_pos, self_ability, enemy_ability, self_protect, enemy_protect], name='input_concat')
        y = input_label

        nl = tf.nn.tanh

        def conv_pip(name, x):
            with tf.name_scope(name) as scope:
                x = conv2d('0', x, config.data_shape[3]*2, kernel=3, stride=1, nl=nl)
                x = conv2d('1', x, config.data_shape[3], kernel=3, stride=1, nl=nl)
            return x

        pred = conv_pip('conv0', x)
        for layer in range(5):
            pred_branch = tf.concat(3, [pred,x], name='concate%d'%layer)
            pred += conv_pip('conv%d'%(layer+1), pred_branch)

        x = tf.tanh(pred, name='control_tanh')

        z = tf.mul(tf.exp(x), self_ability)
        z_sum = tf.reduce_sum(z, reduction_indices=[1,2,3], name='partition_function') # partition function

        # another formula of y*logy
        loss = -tf.reduce_sum(tf.mul(x, y), reduction_indices=[1,2,3]) + tf.log(z_sum)
        z_sum = tf.reshape(z_sum, [-1, 1, 1, 1])
        pred = tf.div(z, z_sum, name='predict')
        return Model([self_pos, enemy_pos, self_ability, enemy_ability, self_protect, enemy_protect], input_label, loss, pred, debug=z)

if __name__=='__main__':

    model = get_model('test')
    sess = tf.InteractiveSession()
    sess.run(tf.initialize_all_variables())

    import numpy as np
    x_data = np.random.randint(2, size=[4,100,9,10,16]).astype('float32')
    y_data = np.random.randint(2, size=[100,9,10,16]).astype('float32')

    train_writer = tf.train.SummaryWriter('train_log/', sess.graph)

    input_dict = {}
    for var, data in zip(model.inputs, x_data):
        input_dict[var] = data
    input_dict[model.label] = y_data

    loss_val = model.loss.eval(feed_dict=input_dict)
    pred_val = model.pred.eval(feed_dict=input_dict)
    print(loss_val)
    # print(pred_val)

    pred_val = pred_val.reshape(pred_val.shape[0], -1)
    assert all(abs(pred_val.sum(axis=1)-1.0<1e-6))
    print('model test OK')
<commit_msg>fix bug in graph visualization<commit_after>#!/usr/bin/python3
#-*-coding:utf-8-*-
#$File: model.py
#$Date: Sat May  7 10:59:45 2016
#$Author: Like Ma <milkpku[at]gmail[dot]com>

from config import config

import tensorflow as tf
import functools

from util.model import Model, conv2d

def get_model(name):
    with tf.name_scope(name) as scope:

        self_pos = tf.placeholder(config.dtype, config.data_shape, name='self_pos')
        enemy_pos = tf.placeholder(config.dtype, config.data_shape, name='enemy_pos')
        self_ability = tf.placeholder(config.dtype, config.data_shape, name='self_ability')
        enemy_ability = tf.placeholder(config.dtype, config.data_shape, name='enemy_ability')
        self_protect = tf.placeholder(config.dtype, config.data_shape, name='self_protect')
        enemy_protect = tf.placeholder(config.dtype, config.data_shape, name='enemy_protect')

        input_label = tf.placeholder(config.dtype, config.label_shape, name='input_label')

        x = tf.concat(3, [self_pos, enemy_pos, self_ability, enemy_ability, self_protect, enemy_protect], name='input_concat')
        y = input_label

        nl = tf.nn.tanh

        def conv_pip(name, x):
            with tf.name_scope(name) as scope:
                x = conv2d('0', x, config.data_shape[3]*2, kernel=3, stride=1, nl=nl)
                x = conv2d('1', x, config.data_shape[3], kernel=3, stride=1, nl=nl)
            return x

        pred = conv_pip('conv0', x)
        for layer in range(5):
            pred_branch = tf.concat(3, [pred,x], name='concate%d'%layer)
            pred += conv_pip('conv%d'%(layer+1), pred_branch)

        x = tf.tanh(pred, name='control_tanh')

        z = tf.mul(tf.exp(x), self_ability)
        z_sum = tf.reduce_sum(z, reduction_indices=[1,2,3], name='partition_function') # partition function

        # another formula of y*logy
        loss = -tf.reduce_sum(tf.mul(x, y), reduction_indices=[1,2,3]) + tf.log(z_sum)
        z_sum = tf.reshape(z_sum, [-1, 1, 1, 1])
        pred = tf.div(z, z_sum, name='predict')
        return Model([self_pos, enemy_pos, self_ability, enemy_ability, self_protect, enemy_protect], input_label, loss, pred, debug=z)

if __name__=='__main__':

    model = get_model('test')
    sess = tf.InteractiveSession()
    sess.run(tf.initialize_all_variables())

    import numpy as np
    x_data = np.random.randint(2, size=[6,100,9,10,16]).astype('float32')
    y_data = np.random.randint(2, size=[100,9,10,16]).astype('float32')

    train_writer = tf.train.SummaryWriter('train_log/', sess.graph)

    input_dict = {}
    for var, data in zip(model.inputs, x_data):
        input_dict[var] = data
    input_dict[model.label] = y_data

    loss_val = model.loss.eval(feed_dict=input_dict)
    pred_val = model.pred.eval(feed_dict=input_dict)
    print(loss_val)
    # print(pred_val)

    pred_val = pred_val.reshape(pred_val.shape[0], -1)
    assert all(abs(pred_val.sum(axis=1)-1.0<1e-6))
    print('model test OK')
<|endoftext|>


<commit_before>from ryu.base import app_manager
from ryu.controller import dpset
from ryu.controller import ofp_event
from ryu.controller.handler import CONFIG_DISPATCHER, MAIN_DISPATCHER
from ryu.controller.handler import set_ev_cls
from ryu.ofproto import ofproto_v1_3
from ryu.lib import dpid as dpid_lib
from ryu.lib import stplib
from ryu.lib.packet import packet
from ryu.lib.packet import ethernet
from ryu.lib.packet import ether_types
# Used for topology discover
from ryu.topology import event
from ryu.topology.api import get_host, get_link, get_switch
# Python Standard Library
# import copy
import networkx as nx
import pprint
import logging

class SimpleSwitch13(app_manager.RyuApp):
    OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]
    _CONTEXTS = {
        'stplib': stplib.Stp,
        'dpset': dpset.DPSet
    }

    def __init__(self, *args, **kwargs):
        super(SimpleSwitch13, self).__init__(*args, **kwargs)
        self.stp = kwargs['stplib']
        self.dpset = kwargs['dpset']
        self.mac_to_port = {}
        self.net = nx.DiGraph()
        # Set Log Level
        self.logger.setLevel(logging.DEBUG)

        # Sample of stplib config.
        #  please refer to stplib.Stp.set_config() for details.
        stp_delay = 3
        config = {dpid_lib.str_to_dpid('0000000000000001'):
                    {'bridge': {'priority': 0x1000, 'fwd_delay': stp_delay}},
                  dpid_lib.str_to_dpid('0000000000000006'):
                    {'bridge': {'priority': 0x2000, 'fwd_delay': stp_delay}},
                  dpid_lib.str_to_dpid('0000000000000007'):
                    {'bridge': {'priority': 0x3000, 'fwd_delay': stp_delay}},
                  dpid_lib.str_to_dpid('0000000000000002'):
                    {'bridge': {'priority': 0x4000, 'fwd_delay': stp_delay}},
                  dpid_lib.str_to_dpid('0000000000000003'):
                    {'bridge': {'priority': 0x5000, 'fwd_delay': stp_delay}},
                  dpid_lib.str_to_dpid('0000000000000008'):
                    {'bridge': {'priority': 0x6000, 'fwd_delay': stp_delay}},
                  dpid_lib.str_to_dpid('0000000000000004'):
                    {'bridge': {'priority': 0x7000, 'fwd_delay': stp_delay}},
                  dpid_lib.str_to_dpid('0000000000000009'):
                    {'bridge': {'priority': 0x8000, 'fwd_delay': stp_delay}},
                  dpid_lib.str_to_dpid('0000000000000005'):
                    {'bridge': {'priority': 0x9000, 'fwd_delay': stp_delay}},
                  dpid_lib.str_to_dpid('0000000000000010'):
                    {'bridge': {'priority': 0xa000, 'fwd_delay': stp_delay}},
                  # Need to configure the Station's STP priority
                  dpid_lib.str_to_dpid('0000000000001002'):
                    {'bridge': {'priority': 0xb000, 'fwd_delay': stp_delay}},
                  dpid_lib.str_to_dpid('0000000000001003'):
                    {'bridge': {'priority': 0xc000, 'fwd_delay': stp_delay}},
                  dpid_lib.str_to_dpid('0000000000001004'):
                    {'bridge': {'priority': 0xd000, 'fwd_delay': stp_delay}},
                  dpid_lib.str_to_dpid('0000000000001005'):
                    {'bridge': {'priority': 0xe000, 'fwd_delay': stp_delay}},
                  dpid_lib.str_to_dpid('0000000000001007'):
                    {'bridge': {'priority': 0xf000, 'fwd_delay': stp_delay}},
                  dpid_lib.str_to_dpid('0000000000001008'):
                    {'bridge': {'priority': 0x10000, 'fwd_delay': stp_delay}},
                  dpid_lib.str_to_dpid('0000000000001009'):
                    {'bridge': {'priority': 0x11000, 'fwd_delay': stp_delay}},
                  dpid_lib.str_to_dpid('0000000000001010'):
                    {'bridge': {'priority': 0x12000, 'fwd_delay': stp_delay}}}
        self.stp.set_config(config)
        # self.logger.debug('[STP] Configuring STP Priority and Fwd_delay')

    # Handy function that lists all attributes in the given object
    def ls(self, obj):
        print("\n".join([x for x in dir(obj) if x[0] != "_"]))

    def add_flow(self, datapath, priority, match, actions):
        ofproto = datapath.ofproto
        parser = datapath.ofproto_parser
        inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,
                                             actions)]
        mod = parser.OFPFlowMod(datapath=datapath, priority=priority,
                                match=match, instructions=inst)
        datapath.send_msg(mod)
        # self.logger.debug('[ADD_FLOW] dpid=')

    def delete_flow(self, datapath, dst_mac):
        ofproto = datapath.ofproto
        parser = datapath.ofproto_parser
        match = parser.OFPMatch(eth_dst=dst_mac)
        mod = parser.OFPFlowMod(datapath, command=ofproto.OFPFC_DELETE,
                                out_port=ofproto.OFPP_ANY,
                                out_group=ofproto.OFPG_ANY,
                                priority=1, match=match)
        datapath.send_msg(mod)

    def get_network_topology(self, ev):
        self.net.clear()
        # Getting Switches Info (Nodes)
        switch_list = get_switch(self, None)
        for switch in switch_list:
            self.net.add_node(switch.dp.id)
        # Getting Links Info
        links_list = get_link(self, None)
        for link in links_list:
            src_dpid = link.src.dpid
            dst_dpid = link.dst.dpid
            src_port_no = link.src.port_no
            dst_port_no = link.dst.port_no
            # Adding links do Directions Graph
            self.net.add_edge(src_dpid, dst_dpid, {'port': src_port_no})
            self.net.add_edge(dst_dpid, src_dpid, {'port': dst_port_no})
        # self.logger.debug("[NetworkX] -- Topology Complete")

    def get_dst_by_src(self, src_node, src_port):
        """ Search for destination DPID or MAC by Source(DPID OR MAC)
            and Source Port
        """
        for src, dst, port in self.net.edges(data='port'):
            if src == src_node and port == src_port:
                return dst

    # -------------------- Topology events --------------------
    @set_ev_cls(event.EventSwitchEnter)
    def switch_enter_handler(self, ev):
        # self.logger.debug("[Event] -- SwitchEnter")
        self.get_network_topology(ev)

    # -------------------- OpenFlow events --------------------
    @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
    def switch_features_handler(self, ev):
        datapath = ev.msg.datapath
        ofproto = datapath.ofproto
        parser = datapath.ofproto_parser

        # install table-miss flow entry
        #
        # We specify NO BUFFER to max_len of the output action due to
        # OVS bug. At this moment, if we specify a lesser number, e.g.,
        # 128, OVS will send Packet-In with invalid buffer_id and
        # truncated packet data. In that case, we cannot output packets
        # correctly.
        match = parser.OFPMatch()
        actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER,
                                          ofproto.OFPCML_NO_BUFFER)]
        self.add_flow(datapath, 0, match, actions)

    @set_ev_cls(ofp_event.EventOFPPortStatus, MAIN_DISPATCHER)
    def _port_status_handler(self, ev):
        msg = ev.msg
        datapath = msg.datapath
        ofproto = datapath.ofproto
        ofpport = msg.desc
        dpid_str = dpid_lib.dpid_to_str(datapath.id)
        # Detecting a host down (Possibly moving?)
        if msg.reason == ofproto.OFPPR_MODIFY \
                and ofpport.state == ofproto.OFPPS_LINK_DOWN:
            # Clear the NetworkGraph when detect LINK_DOWN
            port_no = ofpport.port_no
            dst_node = self.get_dst_by_src(datapath.id, port_no)
            if not None and dst_node in self.net:
                self.logger.info("[HOST DOWN] Removing [mac %s] on " +
                                 "[dpid=%s] [port=%d]",
                                 dst_node, dpid_str, port_no)
                # removing node from Graph
                self.net.remove_node(dst_node)
                # Clearing old flows (relates to host MAC)
                for dp_id, datapath in self.dpset.get_all():
                    self.delete_flow(datapath, dst_node)

    @set_ev_cls(stplib.EventPacketIn, MAIN_DISPATCHER)
    def _packet_in_handler(self, ev):

        # Discards truncated packets
        # If you hit this you might want to increase
        # the "miss_send_length" of your switch
        # if ev.msg.msg_len < ev.msg.total_len:
            # self.logger.debug("Packet truncated: only %s of %s bytes",
            #                   ev.msg.msg_len, ev.msg.total_len)
        msg = ev.msg
        datapath = msg.datapath
        ofproto = datapath.ofproto
        parser = datapath.ofproto_parser
        in_port = msg.match['in_port']
        pkt = packet.Packet(msg.data)
        eth = pkt.get_protocols(ethernet.ethernet)[0]

        # Ignoring lldp packet
        if eth.ethertype == ether_types.ETH_TYPE_LLDP:
            return

        dst = eth.dst
        src = eth.src
        dpid = datapath.id
        self.mac_to_port.setdefault(dpid, {})
        # Logging Packet in event
        # self.logger.info("Packet in %s %s %s %s", dpid, src, dst, in_port)

        # learn a mac address to avoid FLOOD next time. Save the MAC/PORT
        # to update the network topology later
        # self.mac_to_port[dpid][src] = in_port
        if src not in self.net:
            self.net.add_node(src)
            self.net.add_edge(dpid, src, {'port': in_port})
            self.net.add_edge(src, dpid)
        # Try to get the destination from Network Graph
        # out_port fetched from NetworkX
        # if dst in self.mac_to_port[dpid]:
        #     out_port = self.mac_to_port[dpid][dst]
        # else:
        #     out_port = ofproto.OFPP_FLOOD
        if dst in self.net:
            try:
                path = nx.shortest_path(self.net, src, dst)
                next_hop = path[path.index(dpid) + 1]
                out_port = self.net[dpid][next_hop]['port']
            except:
                out_port = ofproto.OFPP_FLOOD
                self.logger.debug('[WARNING] Host in list but no path')
        else:
            out_port = ofproto.OFPP_FLOOD
        # Create OpenFlow Action (Out in port...)
        actions = [parser.OFPActionOutput(out_port)]

        # Install a flow in switch to avoid pkt_in next time
        if out_port != ofproto.OFPP_FLOOD:
            match = parser.OFPMatch(in_port=in_port, eth_dst=dst)
            self.add_flow(datapath, 1, match, actions)

        data = None
        if msg.buffer_id == ofproto.OFP_NO_BUFFER:
            data = msg.data

        out = parser.OFPPacketOut(datapath=datapath, buffer_id=msg.buffer_id,
                                  in_port=in_port, actions=actions, data=data)
        datapath.send_msg(out)

    @set_ev_cls(stplib.EventTopologyChange, MAIN_DISPATCHER)
    def _topology_change_handler(self, ev):
        pass
        # dp = ev.dp
        # dpid_str = dpid_lib.dpid_to_str(dp.id)
        # self.logger.debug(
        #     "[Event] Topology Change: dpid=%s: Flushing MAC table",
        #     dpid_str)

        # if dp.id in self.mac_to_port:
        #     self.delete_flow(dp)
        #     del self.mac_to_port[dp.id]
        # # Update topology
        # self.get_network_topology(ev)

    # @set_ev_cls(stplib.EventPortStateChange, MAIN_DISPATCHER)
    # def _port_state_change_handler(self, ev):
    #     pprint(ev)
    #     dpid_str = dpid_lib.dpid_to_str(ev.dp.id)
    #     of_state = {stplib.PORT_STATE_DISABLE: 'DISABLE',
    #                 stplib.PORT_STATE_BLOCK: 'BLOCK',
    #                 stplib.PORT_STATE_LISTEN: 'LISTEN',
    #                 stplib.PORT_STATE_LEARN: 'LEARN',
    #                 stplib.PORT_STATE_FORWARD: 'FORWARD'}
    #     self.logger.debug("[dpid=%s][port=%d] state=%s",
    #                       dpid_str, ev.port_no, of_state[ev.port_state])
<commit_msg>Está dando erro<commit_after>from ryu.base import app_manager
from ryu.controller import dpset
from ryu.controller import ofp_event
from ryu.controller.handler import CONFIG_DISPATCHER, MAIN_DISPATCHER
from ryu.controller.handler import set_ev_cls
from ryu.ofproto import ofproto_v1_3
from ryu.lib import dpid as dpid_lib
from ryu.lib import stplib
from ryu.lib.packet import packet
from ryu.lib.packet import ethernet
from ryu.lib.packet import ether_types
# Used for topology discover
from ryu.topology import event
from ryu.topology.api import get_host, get_link, get_switch
# Python Standard Library
# import copy
import networkx as nx
import pprint
import logging

class SimpleSwitch13(app_manager.RyuApp):
    OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]
    _CONTEXTS = {
        'stplib': stplib.Stp,
        'dpset': dpset.DPSet
    }

    def __init__(self, *args, **kwargs):
        super(SimpleSwitch13, self).__init__(*args, **kwargs)
        self.stp = kwargs['stplib']
        self.dpset = kwargs['dpset']
        self.mac_to_port = {}
        self.net = nx.DiGraph()
        # Set Log Level
        self.logger.setLevel(logging.DEBUG)

        # Sample of stplib config.
        #  please refer to stplib.Stp.set_config() for details.
        stp_hello = 1
        stp_delay = 2
        config = {dpid_lib.str_to_dpid('0000000000000001'):
                    {'bridge': {'priority': 0x1000, 'fwd_delay': stp_delay,
                     'hello_time': stp_hello}},
                  dpid_lib.str_to_dpid('0000000000000006'):
                    {'bridge': {'priority': 0x2000, 'fwd_delay': stp_delay,
                     'hello_time': stp_hello}},
                  dpid_lib.str_to_dpid('0000000000000007'):
                    {'bridge': {'priority': 0x3000, 'fwd_delay': stp_delay,
                     'hello_time': stp_hello}},
                  dpid_lib.str_to_dpid('0000000000000002'):
                    {'bridge': {'priority': 0x4000, 'fwd_delay': stp_delay,
                     'hello_time': stp_hello}},
                  dpid_lib.str_to_dpid('0000000000000003'):
                    {'bridge': {'priority': 0x5000, 'fwd_delay': stp_delay,
                     'hello_time': stp_hello}},
                  dpid_lib.str_to_dpid('0000000000000008'):
                    {'bridge': {'priority': 0x6000, 'fwd_delay': stp_delay,
                     'hello_time': stp_hello}},
                  dpid_lib.str_to_dpid('0000000000000004'):
                    {'bridge': {'priority': 0x7000, 'fwd_delay': stp_delay,
                     'hello_time': stp_hello}},
                  dpid_lib.str_to_dpid('0000000000000009'):
                    {'bridge': {'priority': 0x8000, 'fwd_delay': stp_delay,
                     'hello_time': stp_hello}},
                  dpid_lib.str_to_dpid('0000000000000005'):
                    {'bridge': {'priority': 0x9000, 'fwd_delay': stp_delay,
                     'hello_time': stp_hello}},
                  dpid_lib.str_to_dpid('0000000000000010'):
                    {'bridge': {'priority': 0xa000, 'fwd_delay': stp_delay,
                     'hello_time': stp_hello}},
                  # Need to configure the Station's STP priority
                  dpid_lib.str_to_dpid('0000000000001002'):
                    {'bridge': {'priority': 0xb000, 'fwd_delay': stp_delay,
                     'hello_time': stp_hello}},
                  dpid_lib.str_to_dpid('0000000000001003'):
                    {'bridge': {'priority': 0xc000, 'fwd_delay': stp_delay,
                     'hello_time': stp_hello}},
                  dpid_lib.str_to_dpid('0000000000001004'):
                    {'bridge': {'priority': 0xd000, 'fwd_delay': stp_delay,
                     'hello_time': stp_hello}},
                  dpid_lib.str_to_dpid('0000000000001005'):
                    {'bridge': {'priority': 0xe000, 'fwd_delay': stp_delay,
                     'hello_time': stp_hello}},
                  dpid_lib.str_to_dpid('0000000000001007'):
                    {'bridge': {'priority': 0xf000, 'fwd_delay': stp_delay,
                     'hello_time': stp_hello}},
                  dpid_lib.str_to_dpid('0000000000001008'):
                    {'bridge': {'priority': 0x10000, 'fwd_delay': stp_delay,
                     'hello_time': stp_hello}},
                  dpid_lib.str_to_dpid('0000000000001009'):
                    {'bridge': {'priority': 0x11000, 'fwd_delay': stp_delay,
                     'hello_time': stp_hello}},
                  dpid_lib.str_to_dpid('0000000000001010'):
                    {'bridge': {'priority': 0x12000, 'fwd_delay': stp_delay,
                     'hello_time': stp_hello}}}
        self.stp.set_config(config)
        # self.logger.debug('[STP] Configuring STP Priority and Fwd_delay')

    # Handy function that lists all attributes in the given object
    def ls(self, obj):
        print("\n".join([x for x in dir(obj) if x[0] != "_"]))

    def add_flow(self, datapath, priority, match, actions):
        ofproto = datapath.ofproto
        parser = datapath.ofproto_parser
        inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,
                                             actions)]
        mod = parser.OFPFlowMod(datapath=datapath, priority=priority,
                                match=match, instructions=inst)
        datapath.send_msg(mod)
        # self.logger.debug('[ADD_FLOW] dpid=')

    def delete_flow(self, datapath, dst_mac):
        ofproto = datapath.ofproto
        parser = datapath.ofproto_parser
        match = parser.OFPMatch(eth_dst=dst_mac)
        mod = parser.OFPFlowMod(datapath, command=ofproto.OFPFC_DELETE,
                                out_port=ofproto.OFPP_ANY,
                                out_group=ofproto.OFPG_ANY,
                                priority=1, match=match)
        datapath.send_msg(mod)

    def get_network_topology(self, ev):
        self.net.clear()
        # Getting Switches Info (Nodes)
        switch_list = get_switch(self, None)
        for switch in switch_list:
            self.net.add_node(switch.dp.id)
        # Getting Links Info
        links_list = get_link(self, None)
        for link in links_list:
            src_dpid = link.src.dpid
            dst_dpid = link.dst.dpid
            src_port_no = link.src.port_no
            dst_port_no = link.dst.port_no
            # Adding links do Directions Graph
            self.net.add_edge(src_dpid, dst_dpid, {'port': src_port_no})
            self.net.add_edge(dst_dpid, src_dpid, {'port': dst_port_no})
        # self.logger.debug("[NetworkX] -- Topology Complete")

    def get_dst_by_src(self, src_node, src_port):
        """ Search for destination DPID or MAC by Source(DPID OR MAC)
            and Source Port
        """
        for src, dst, port in self.net.edges(data='port'):
            if src == src_node and port == src_port:
                return dst

    # -------------------- Topology events --------------------
    @set_ev_cls(event.EventSwitchEnter)
    def switch_enter_handler(self, ev):
        # self.logger.debug("[Event] -- SwitchEnter")
        self.get_network_topology(ev)

    # -------------------- OpenFlow events --------------------
    @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
    def switch_features_handler(self, ev):
        datapath = ev.msg.datapath
        ofproto = datapath.ofproto
        parser = datapath.ofproto_parser

        # install table-miss flow entry
        #
        # We specify NO BUFFER to max_len of the output action due to
        # OVS bug. At this moment, if we specify a lesser number, e.g.,
        # 128, OVS will send Packet-In with invalid buffer_id and
        # truncated packet data. In that case, we cannot output packets
        # correctly.
        match = parser.OFPMatch()
        actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER,
                                          ofproto.OFPCML_NO_BUFFER)]
        self.add_flow(datapath, 0, match, actions)

    @set_ev_cls(ofp_event.EventOFPPortStatus, MAIN_DISPATCHER)
    def _port_status_handler(self, ev):
        msg = ev.msg
        datapath = msg.datapath
        ofproto = datapath.ofproto
        ofpport = msg.desc
        dpid_str = dpid_lib.dpid_to_str(datapath.id)
        # Detecting a host down (Possibly moving?)
        if msg.reason == ofproto.OFPPR_MODIFY \
                and ofpport.state == ofproto.OFPPS_LINK_DOWN:
            # Clear the NetworkGraph when detect LINK_DOWN
            port_no = ofpport.port_no
            dst_node = self.get_dst_by_src(datapath.id, port_no)
            if not None and dst_node in self.net:
                self.logger.info("[HOST DOWN] Removing [mac %s] on " +
                                 "[dpid=%s] [port=%d]",
                                 dst_node, dpid_str, port_no)
                # removing node from Graph
                self.net.remove_node(dst_node)
                # Clearing old flows (relates to host MAC)
                for dp_id, datapath in self.dpset.get_all():
                    self.delete_flow(datapath, dst_node)

    @set_ev_cls(stplib.EventPacketIn, MAIN_DISPATCHER)
    def _packet_in_handler(self, ev):

        # Discards truncated packets
        # If you hit this you might want to increase
        # the "miss_send_length" of your switch
        # if ev.msg.msg_len < ev.msg.total_len:
            # self.logger.debug("Packet truncated: only %s of %s bytes",
            #                   ev.msg.msg_len, ev.msg.total_len)
        msg = ev.msg
        datapath = msg.datapath
        ofproto = datapath.ofproto
        parser = datapath.ofproto_parser
        in_port = msg.match['in_port']
        pkt = packet.Packet(msg.data)
        eth = pkt.get_protocols(ethernet.ethernet)[0]

        # Ignoring lldp packet
        if eth.ethertype == ether_types.ETH_TYPE_LLDP:
            return

        dst = eth.dst
        src = eth.src
        dpid = datapath.id
        self.mac_to_port.setdefault(dpid, {})
        # Logging Packet in event
        # self.logger.info("Packet in %s %s %s %s", dpid, src, dst, in_port)

        # learn a mac address to avoid FLOOD next time. Save the MAC/PORT
        # to update the network topology later
        # self.mac_to_port[dpid][src] = in_port
        if src not in self.net:
            self.net.add_node(src)
            self.net.add_edge(dpid, src, {'port': in_port})
            self.net.add_edge(src, dpid)
        # Try to get the destination from Network Graph
        # out_port fetched from NetworkX
        # if dst in self.mac_to_port[dpid]:
        #     out_port = self.mac_to_port[dpid][dst]
        # else:
        #     out_port = ofproto.OFPP_FLOOD
        if dst in self.net:
            try:
                path = nx.shortest_path(self.net, src, dst)
                next_hop = path[path.index(dpid) + 1]
                out_port = self.net[dpid][next_hop]['port']
            except:
                out_port = ofproto.OFPP_FLOOD
                self.logger.debug('[WARNING] Host in list but no path')
        else:
            out_port = ofproto.OFPP_FLOOD
        # Create OpenFlow Action (Out in port...)
        actions = [parser.OFPActionOutput(out_port)]

        # Install a flow in switch to avoid pkt_in next time
        if out_port != ofproto.OFPP_FLOOD:
            match = parser.OFPMatch(in_port=in_port, eth_dst=dst)
            self.add_flow(datapath, 1, match, actions)

        data = None
        if msg.buffer_id == ofproto.OFP_NO_BUFFER:
            data = msg.data

        out = parser.OFPPacketOut(datapath=datapath, buffer_id=msg.buffer_id,
                                  in_port=in_port, actions=actions, data=data)
        datapath.send_msg(out)

    @set_ev_cls(stplib.EventTopologyChange, MAIN_DISPATCHER)
    def _topology_change_handler(self, ev):
        pass
        # dp = ev.dp
        # dpid_str = dpid_lib.dpid_to_str(dp.id)
        # self.logger.debug(
        #     "[Event] Topology Change: dpid=%s: Flushing MAC table",
        #     dpid_str)

        # if dp.id in self.mac_to_port:
        #     self.delete_flow(dp)
        #     del self.mac_to_port[dp.id]
        # # Update topology
        # self.get_network_topology(ev)

    # @set_ev_cls(stplib.EventPortStateChange, MAIN_DISPATCHER)
    # def _port_state_change_handler(self, ev):
    #     pprint(ev)
    #     dpid_str = dpid_lib.dpid_to_str(ev.dp.id)
    #     of_state = {stplib.PORT_STATE_DISABLE: 'DISABLE',
    #                 stplib.PORT_STATE_BLOCK: 'BLOCK',
    #                 stplib.PORT_STATE_LISTEN: 'LISTEN',
    #                 stplib.PORT_STATE_LEARN: 'LEARN',
    #                 stplib.PORT_STATE_FORWARD: 'FORWARD'}
    #     self.logger.debug("[dpid=%s][port=%d] state=%s",
    #                       dpid_str, ev.port_no, of_state[ev.port_state])
<|endoftext|>


<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-
from sqlalchemy.engine import reflection
from sqlalchemy import Table, Column, Integer, String, MetaData, ForeignKey, \
    update, delete, select
from sqlalchemy.schema import (
    MetaData,
    Table,
    DropTable,
    ForeignKeyConstraint,
    DropConstraint
)
import re
from core import db
from utilities.models import get_model_name

class Model(object):
    def __init__(self, context):
            self.context = context

    def getRef(self):
        return self.ref

    def getMetadata(self):
        return self.context.metadata

    def getName(self):
        return self.ref.name

    def getNormalizedName(self):
        return self.__normalized_name

    def generate(self):
        if db.DB().hasConfig('prefix'):
            self.__prefix = db.DB().getConfig('prefix')
            self.__normalized_name = self.ref.name
            self.ref.name = self.__prefix + "_" + self.ref.name
        self.ref.create(db.DB().getEngine(), checkfirst=True)
        return self

    def getConstraints(self):
        inspector = reflection.Inspector.from_engine(db.DB().getEngine())
        fks = []
        for fk in inspector.get_foreign_keys(self.ref.name):
            if not fk['name']:
                continue
            fks.append(ForeignKeyConstraint((), (), name=fk['name']))
        return fks

    def getDependencies(self):
        ret = []
        fks = self.ref.foreign_keys
        for fk in fks:
            str_ref = vars(fk)["_colspec"]
            contents = re.match("(.*)\.(.*)", str_ref)
            str_ref_table = contents.group(1)
            str_ref_col = contents.group(2)
            ret.append({
                'reference' : str_ref,
                'referenced_table' : str_ref_table,
                'referenced_model' : get_model_name(str_ref_table),
                'referenced_col' : str_ref_col,
                'referencing_col' : vars(vars(fk)["parent"])["key"]
            })
        return ret

    def getForeignKeys(self, table_name):
        if not db.DB().getEngine().has_table(self.ref.name):
            return []
        inspector = reflection.Inspector.from_engine(db.DB().getEngine())
        return inspector.get_foreign_keys(table_name)

    def obliterate(self):
        if db.DB().hasConfig('prefix'):
            self.ref.name = db.DB().getConfig('prefix') + "_" + self.ref.name
        if not db.DB().getEngine().has_table(self.ref.name):
            return self

        fks = self.getConstraints()
        Table(self.ref.name, MetaData(), *fks)
        for fk in fks:
            self.execute(DropConstraint(fk))

        self.ref.drop(db.DB().getEngine(), checkfirst=True)
        return self

    def col(self, val):
        return self.ref.c[val]

    def execute(self, stmt):
        return db.DB().getConnection().execute(stmt)

    def insert(self, values):
        result = db.DB().getConnection().execute(self.ref.insert().values(values))
        return result.inserted_primary_key

    def insertMany(self, values):
        db.DB().getConnection().execute(self.ref.insert(), values)

    # http://docs.sqlalchemy.org/en/rel_0_9/core/tutorial.html
    # http://docs.sqlalchemy.org/en/latest/core/sqlelement.html#sqlalchemy.sql.expression.ColumnElement
    def update(self, values=None, where=None):
        stmt = update(self.ref, where, values)
        result = self.execute(stmt)
        return result.rowcount

    def delete(self, where):
        if where is not None:
            stmt = delete(self.ref, where)
            result = self.execute(stmt)
            return result.rowcount
        else:
            return 0

    def select(self, columns=None, whereclause=None):
        stmt = select(columns=columns, whereclause=whereclause)
        result = self.execute(stmt)
        return result

    def selectAll(self):
        stmt = select([self.ref])
        result = self.execute(stmt)
        return result

    def selectValue(self, column, whereclause=None):
        result = self.selectOne([self.col(column)], whereclause)
        for res in result:
            return res[self.col(column)]
        else:
            return False
        return False

    def selectOne(self, columns=None, whereclause=None):
        stmt = select(columns=columns, whereclause=whereclause).limit(1)
        result = self.execute(stmt)
        return result

    def existsBy(self, by_col, by_val):
        select_value = self.selectValue(by_col, self.col(by_col) == by_val)
        return select_value is not False
<commit_msg>minor fix: always set normalised name on generate<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-
from sqlalchemy.engine import reflection
from sqlalchemy import Table, Column, Integer, String, MetaData, ForeignKey, \
    update, delete, select
from sqlalchemy.schema import (
    MetaData,
    Table,
    DropTable,
    ForeignKeyConstraint,
    DropConstraint
)
import re
from core import db
from utilities.models import get_model_name

class Model(object):
    def __init__(self, context):
            self.context = context

    def getRef(self):
        return self.ref

    def getMetadata(self):
        return self.context.metadata

    def getName(self):
        return self.ref.name

    def getNormalizedName(self):
        return self.__normalized_name

    def generate(self):
        if db.DB().hasConfig('prefix'):
            self.__prefix = db.DB().getConfig('prefix')
            self.ref.name = self.__prefix + "_" + self.ref.name
        self.__normalized_name = self.ref.name
        self.ref.create(db.DB().getEngine(), checkfirst=True)
        return self

    def getConstraints(self):
        inspector = reflection.Inspector.from_engine(db.DB().getEngine())
        fks = []
        for fk in inspector.get_foreign_keys(self.ref.name):
            if not fk['name']:
                continue
            fks.append(ForeignKeyConstraint((), (), name=fk['name']))
        return fks

    def getDependencies(self):
        ret = []
        fks = self.ref.foreign_keys
        for fk in fks:
            str_ref = vars(fk)["_colspec"]
            contents = re.match("(.*)\.(.*)", str_ref)
            str_ref_table = contents.group(1)
            str_ref_col = contents.group(2)
            ret.append({
                'reference' : str_ref,
                'referenced_table' : str_ref_table,
                'referenced_model' : get_model_name(str_ref_table),
                'referenced_col' : str_ref_col,
                'referencing_col' : vars(vars(fk)["parent"])["key"]
            })
        return ret

    def getForeignKeys(self, table_name):
        if not db.DB().getEngine().has_table(self.ref.name):
            return []
        inspector = reflection.Inspector.from_engine(db.DB().getEngine())
        return inspector.get_foreign_keys(table_name)

    def obliterate(self):
        if db.DB().hasConfig('prefix'):
            self.ref.name = db.DB().getConfig('prefix') + "_" + self.ref.name
        if not db.DB().getEngine().has_table(self.ref.name):
            return self

        fks = self.getConstraints()
        Table(self.ref.name, MetaData(), *fks)
        for fk in fks:
            self.execute(DropConstraint(fk))

        self.ref.drop(db.DB().getEngine(), checkfirst=True)
        return self

    def col(self, val):
        return self.ref.c[val]

    def execute(self, stmt):
        return db.DB().getConnection().execute(stmt)

    def insert(self, values):
        result = db.DB().getConnection().execute(self.ref.insert().values(values))
        return result.inserted_primary_key

    def insertMany(self, values):
        db.DB().getConnection().execute(self.ref.insert(), values)

    # http://docs.sqlalchemy.org/en/rel_0_9/core/tutorial.html
    # http://docs.sqlalchemy.org/en/latest/core/sqlelement.html#sqlalchemy.sql.expression.ColumnElement
    def update(self, values=None, where=None):
        stmt = update(self.ref, where, values)
        result = self.execute(stmt)
        return result.rowcount

    def delete(self, where):
        if where is not None:
            stmt = delete(self.ref, where)
            result = self.execute(stmt)
            return result.rowcount
        else:
            return 0

    def select(self, columns=None, whereclause=None):
        stmt = select(columns=columns, whereclause=whereclause)
        result = self.execute(stmt)
        return result

    def selectAll(self):
        stmt = select([self.ref])
        result = self.execute(stmt)
        return result

    def selectValue(self, column, whereclause=None):
        result = self.selectOne([self.col(column)], whereclause)
        for res in result:
            return res[self.col(column)]
        else:
            return False
        return False

    def selectOne(self, columns=None, whereclause=None):
        stmt = select(columns=columns, whereclause=whereclause).limit(1)
        result = self.execute(stmt)
        return result

    def existsBy(self, by_col, by_val):
        select_value = self.selectValue(by_col, self.col(by_col) == by_val)
        return select_value is not False
<|endoftext|>


<commit_before>#
# This example demonstrates an experimental feature: Text reconstruction
# The Reconstructor takes a parse tree (already filtered from punctuation, of course),
# and reconstructs it into correct text, that can be parsed correctly.
# It can be useful for creating "hooks" to alter data before handing it to other parsers. You can also use it to generate samples from scratch.
#

import json
from .json_parser import json_grammar

from lark import Lark
from lark.reconstruct import Reconstructor

def test():

    test_json = '''
        {
            "empty_object" : {},
            "empty_array"  : [],
            "booleans"     : { "YES" : true, "NO" : false },
            "numbers"      : [ 0, 1, -2, 3.3, 4.4e5, 6.6e-7 ],
            "strings"      : [ "This", [ "And" , "That" ] ],
            "nothing"      : null
        }
    '''

    json_parser = Lark(json_grammar)
    tree = json_parser.parse(test_json)

    # print '@@', tree.pretty()
    # for x in tree.find_data('true'):
    #     x.data = 'false'
    #     # x.children[0].value = '"HAHA"'

    new_json = Reconstructor(json_parser).reconstruct(tree)
    print new_json
    print json.loads(new_json) == json.loads(test_json)

test()
<commit_msg>Tiny fix in reconstruct_json (Py3)<commit_after>#
# This example demonstrates an experimental feature: Text reconstruction
# The Reconstructor takes a parse tree (already filtered from punctuation, of course),
# and reconstructs it into correct text, that can be parsed correctly.
# It can be useful for creating "hooks" to alter data before handing it to other parsers. You can also use it to generate samples from scratch.
#

import json
from .json_parser import json_grammar

from lark import Lark
from lark.reconstruct import Reconstructor

def test():

    test_json = '''
        {
            "empty_object" : {},
            "empty_array"  : [],
            "booleans"     : { "YES" : true, "NO" : false },
            "numbers"      : [ 0, 1, -2, 3.3, 4.4e5, 6.6e-7 ],
            "strings"      : [ "This", [ "And" , "That" ] ],
            "nothing"      : null
        }
    '''

    json_parser = Lark(json_grammar)
    tree = json_parser.parse(test_json)

    # print ('@@', tree.pretty())
    # for x in tree.find_data('true'):
    #     x.data = 'false'
    #     # x.children[0].value = '"HAHA"'

    new_json = Reconstructor(json_parser).reconstruct(tree)
    print (new_json)
    print (json.loads(new_json) == json.loads(test_json))

test()
<|endoftext|>


<commit_before>
import os
import json

class JSONConfigLoader():
    def __init__(self):
        self.sources = [
            os.path.dirname(os.getcwd()),
            os.path.dirname(os.path.abspath(__file__)),
            os.path.expanduser('~'),
            '/etc',
        ]

    def load(self, filename):
        for source in self.sources:
            file_path = os.path.join(source, filename)
            if not os.path.exists(file_path):
                continue
            with open(file_path) as f:
                return json.load(f)

        return None
<commit_msg>Raise exception in case of config load error<commit_after>
import os
import json

class JSONConfigLoader():
    def __init__(self, base_path):
        self.sources = [
            os.path.dirname(os.getcwd()),
            os.path.dirname(os.path.abspath(base_path)),
            os.path.expanduser('~'),
            '/etc',
        ]

    def load(self, filename):
        tries = []
        for source in self.sources:
            file_path = os.path.join(source, filename)
            tries.append(file_path)
            if not os.path.exists(file_path):
                continue
            with open(file_path) as f:
                return json.load(f)

        raise Exception("Config file not found in: %s" % tries)
<|endoftext|>


<commit_before>__version_info__ = ('0', '0', '1')
__version__ = '.'.join(__version_info__)
__short_version__ = '.'.join(__version_info__)
__author__ = 'Stormpath, Inc.'
__license__ = 'Apache'
__copyright__ = '(c) 2012 - 2014 Stormpath, Inc.'
<commit_msg>Version bump.<commit_after>__version_info__ = ('0', '0', '2')
__version__ = '.'.join(__version_info__)
__short_version__ = '.'.join(__version_info__)
__author__ = 'Stormpath, Inc.'
__license__ = 'Apache'
__copyright__ = '(c) 2012 - 2014 Stormpath, Inc.'
<|endoftext|>


<commit_before># Copyright (c) 2013, Universal Resource Trading Limited and contributors
# For license information, please see license.txt

from __future__ import unicode_literals
from __future__ import print_function
import __builtin__ as builtins

import sys
import os.path

import frappe
from frappe import msgprint
#from frappe.utils import cstr

sys.path.insert(0, frappe.get_app_path('erpnext_ebay'))
sys.path.insert(0, "/Users/ben/dev/ebaysdk-python/dist/ebaysdk-2.1.5-py2.7.egg")
sys.path.insert(0, "/usr/local/lib/python2.7/dist-packages/ebaysdk-2.1.4-py2.7.egg")
sys.path.insert(0, "/usr/local/lib/python2.7/dist-packages/lxml-3.6.4-py2.7-linux-i686.egg")

from ebaysdk.exception import ConnectionError
from ebaysdk.trading import Connection as Trading
from garage_sale import jtemplate, lookup_condition
import ugssettings

PATH_TO_YAML = os.path.join(os.sep, frappe.utils.get_bench_path(), 'sites', \
               frappe.get_site_path(), 'ebay.yaml')

@frappe.whitelist(allow_guest=True)
def revise_generic_items(item_code):
    """Generic Revise eBay listings

    """

    #get the ebay id given the item_code
    ebay_id = frappe.get_value('Item', item_code, 'ebay_id')
    if ebay_id and item_code:
        frappe.msgprint('This Item is on eBay. Please wait while the listing is revised...')

        item_name,\
        description,\
        function_grade,\
        grade_details,\
        condition,\
        tech_details,\
        delivery_type,\
        accessories_extras,\
        power_cable_included,\
        power_supply_included,\
        remote_control_included,\
        case_included,\
        warranty_period\
         = get_item_revisions(item_code)

        version = 0

        body = """<![CDATA["""
        body += jtemplate(version, description, function_grade, grade_details, condition, \
                tech_details, delivery_type, accessories_extras, \
                power_cable_included, power_supply_included, remote_control_included, \
                case_included, warranty_period)
        body += "

The price includes VAT and we can provide VAT invoices."
        body += "

Universities and colleges - purchase orders accepted - please contact us."
        body += "

sku: " + item_code
        body += """]]>"""

        condition_description = '' #grade_details
        condition_id_text, condition_id = lookup_condition(condition, 0)

        new_gsp = (delivery_type == 'Standard Parcel')

        try:
            api_trading = Trading(config_file=PATH_TO_YAML, warnings=True, timeout=20)

            #EXAMPLE api.execute('ReviseItem',{'Item':{'ItemID':ItemID},'Title':words}
            api_trading.execute('ReviseItem',{
                'Item':{'ItemID': ebay_id},
                'GlobalShipping': new_gsp,
                'Title': item_name,
                'Description': body,
                'ConditionDescription': condition_description,
                'ConditionID': condition_id
                }
                )

        except ConnectionError:
            frappe.msgprint("Config file ebay.yaml file not found")
            raise

        except Exception:
            frappe.msgprint("There was a problem using the eBay Api")
            raise

        else:
            frappe.msgprint("Success eBay listing updated!")
    else:
        frappe.msgprint("There was a problem getting the data")

def get_item_revisions(item_code):

    sql = """
    select
        it.item_name,
        it.description,
        it.function_grade,
        it.grade_details,
        it.condition,
        it.tech_details,
        it.delivery_type,
        it.accessories_extras,
        it.power_cable_included,
        it.power_supply_included,
        it.remote_control_included,
        it.case_included,
        it.warranty_period,
        it.is_auction
    from `tabItem` it
    where item_code = '{}'
    """.format(item_code)

    records = frappe.db.sql(sql)

    return records[0][0], records[0][1], records[0][2], records[0][3], records[0][4], \
           records[0][5], records[0][6], records[0][7], records[0][8], records[0][9], \
           records[0][10], records[0][11], records[0][12]

@frappe.whitelist(allow_guest=True)
def revise_ebay_price(item_code, new_price, is_auction):
    """Given item_code and price, revise the listing on eBay"""

    #get the ebay id given the item_code
    ebay_id = frappe.get_value('Item', item_code, 'ebay_id')
    if ebay_id and item_code and new_price:

        frappe.msgprint('{} Item is on eBay. Please wait while the listing is revised...').format(item_code)
        new_price_inc = float(new_price) * ugssettings.VAT

        try:
            api_trading = Trading(config_file=PATH_TO_YAML, warnings=True, timeout=20)

            if is_auction:
                api_trading.execute('ReviseItem', {'Item':{'ItemID':ebay_id, \
                                'StartPrice':new_price_inc}})
            else:
                # ReviseInventoryStatus enables change to price and/or quantity of an active, fixed-price listing.
                # The fixed-price listing is identified with the ItemID of the listing or the SKUvalue of the item
                api_trading.execute('ReviseInventoryStatus', {'InventoryStatus':{'ItemID':ebay_id, \
                                    'StartPrice':new_price_inc}})

        except ConnectionError:
            frappe.msgprint("Config file ebay.yaml file not found")
            raise

        except Exception:
            frappe.msgprint("Price sync. There was a problem using the eBay Api")
            raise

        else:
            frappe.msgprint("Price sync success - eBay listing updated! {}".format(item_code))
    else:
        frappe.msgprint("Price Sync Error: There was a problem getting the data")
<commit_msg>testing<commit_after># Copyright (c) 2013, Universal Resource Trading Limited and contributors
# For license information, please see license.txt

from __future__ import unicode_literals
from __future__ import print_function
import __builtin__ as builtins

import sys
import os.path

import frappe
from frappe import msgprint
#from frappe.utils import cstr

sys.path.insert(0, frappe.get_app_path('erpnext_ebay'))
sys.path.insert(0, "/Users/ben/dev/ebaysdk-python/dist/ebaysdk-2.1.5-py2.7.egg")
sys.path.insert(0, "/usr/local/lib/python2.7/dist-packages/ebaysdk-2.1.4-py2.7.egg")
sys.path.insert(0, "/usr/local/lib/python2.7/dist-packages/lxml-3.6.4-py2.7-linux-i686.egg")

from ebaysdk.exception import ConnectionError
from ebaysdk.trading import Connection as Trading
from garage_sale import jtemplate, lookup_condition
import ugssettings

PATH_TO_YAML = os.path.join(os.sep, frappe.utils.get_bench_path(), 'sites', \
               frappe.get_site_path(), 'ebay.yaml')

@frappe.whitelist(allow_guest=True)
def revise_generic_items(item_code):
    """Generic Revise eBay listings

    """

    #get the ebay id given the item_code
    ebay_id = frappe.get_value('Item', item_code, 'ebay_id')
    if ebay_id and item_code:
        frappe.msgprint('This Item is on eBay. Please wait while the listing is revised...')

        item_name,\
        description,\
        function_grade,\
        grade_details,\
        condition,\
        tech_details,\
        delivery_type,\
        accessories_extras,\
        power_cable_included,\
        power_supply_included,\
        remote_control_included,\
        case_included,\
        warranty_period\
         = get_item_revisions(item_code)

        version = 0

        body = """<![CDATA["""
        body += jtemplate(version, description, function_grade, grade_details, condition, \
                tech_details, delivery_type, accessories_extras, \
                power_cable_included, power_supply_included, remote_control_included, \
                case_included, warranty_period)
        body += "

The price includes VAT and we can provide VAT invoices."
        body += "

Universities and colleges - purchase orders accepted - please contact us."
        body += "

sku: " + item_code
        body += """]]>"""

        condition_description = '' #grade_details
        condition_id_text, condition_id = lookup_condition(condition, 0)

        new_gsp = (delivery_type == 'Standard Parcel')

        try:
            api_trading = Trading(config_file=PATH_TO_YAML, warnings=True, timeout=20)

            #EXAMPLE api.execute('ReviseItem',{'Item':{'ItemID':ItemID},'Title':words}
            api_trading.execute('ReviseItem',{
                'Item':{'ItemID': ebay_id},
                'GlobalShipping': new_gsp,
                'Title': item_name,
                'Description': body,
                'ConditionDescription': condition_description,
                'ConditionID': condition_id
                }
                )

        except ConnectionError:
            frappe.msgprint("Config file ebay.yaml file not found")
            raise

        except Exception:
            frappe.msgprint("There was a problem using the eBay Api")
            raise

        else:
            frappe.msgprint("Success eBay listing updated!")
    else:
        frappe.msgprint("There was a problem getting the data")

def get_item_revisions(item_code):

    sql = """
    select
        it.item_name,
        it.description,
        it.function_grade,
        it.grade_details,
        it.condition,
        it.tech_details,
        it.delivery_type,
        it.accessories_extras,
        it.power_cable_included,
        it.power_supply_included,
        it.remote_control_included,
        it.case_included,
        it.warranty_period,
        it.is_auction
    from `tabItem` it
    where item_code = '{}'
    """.format(item_code)

    records = frappe.db.sql(sql)

    return records[0][0], records[0][1], records[0][2], records[0][3], records[0][4], \
           records[0][5], records[0][6], records[0][7], records[0][8], records[0][9], \
           records[0][10], records[0][11], records[0][12]

@frappe.whitelist(allow_guest=True)
def revise_ebay_price(item_code, new_price, is_auction):
    """Given item_code and price, revise the listing on eBay"""

    #get the ebay id given the item_code
    ebay_id = frappe.get_value('Item', item_code, 'ebay_id')
    if ebay_id and item_code and new_price:

        #frappe.msgprint('{} Item is on eBay. Please wait while the listing is revised...'.format(item_code))
        new_price_inc = float(new_price) * ugssettings.VAT

        try:
            api_trading = Trading(config_file=PATH_TO_YAML, warnings=True, timeout=20)

            if is_auction:
                api_trading.execute('ReviseItem', {'Item':{'ItemID':ebay_id, \
                                'StartPrice':new_price_inc}})
            else:
                # ReviseInventoryStatus enables change to price and/or quantity of an active, fixed-price listing.
                # The fixed-price listing is identified with the ItemID of the listing or the SKUvalue of the item
                api_trading.execute('ReviseInventoryStatus', {'InventoryStatus':{'ItemID':ebay_id, \
                                    'StartPrice':new_price_inc}})

        except ConnectionError:
            frappe.msgprint("Config file ebay.yaml file not found")
            raise

        except Exception:
            frappe.msgprint("Price sync. There was a problem using the eBay Api")
            raise

        else:
            frappe.msgprint("Price sync success - eBay listing updated! {}".format(item_code))
    else:
        frappe.msgprint("Price Sync Error: There was a problem getting the data")
<|endoftext|>


<commit_before>"""Base Transitland Entity."""
import json

import mzgeohash

import geom
import util
import errors

class Entity(object):
  """A Transitland Entity."""
  # OnestopID prefix.
  onestop_type = None

  def __init__(self, **data):
    """Set name, Onestop ID, and geometry."""
    if 'onestop_id' in data:
      data['onestopId'] = data.pop('onestop_id')
    self.data = data
    self.parents = set()
    self.children = set()

  # Basic ID, name, geometry...
  def name(self):
    """A reasonable display name for the entity."""
    return self.data.get('name')

  def id(self):
    """Alias to onestop()"""
    return self.onestop()

  def onestop(self):
    """Return the Onestop ID for this entity."""
    return self.data.get('onestopId') or self.make_onestop()

  def make_onestop(self):
    # Check maximum length.
    onestop = '%s-%s-%s'%(
      self.onestop_type,
      self.geohash()[:util.GEOHASH_LENGTH],
      self.mangle(self.name())
    )
    return onestop[:util.ONESTOP_LENGTH]

  def mangle(self, s):
    """Mangle a string into a Onestop component."""
    s = s.lower()
    for a,b in util.REPLACE_CHAR:
      s = a.sub(b,s)
    return s

  # Entity geometry.
  def geohash(self):
    """Return the geohash for this entity."""
    raise NotImplementedError

  def geometry(self):
    """Return a GeoJSON-type geometry for this entity."""
    # TODO: Right now, this has to be supplied by GTFS Entity...
    return self.data.get('geometry')

  def point(self):
    """Return a point for this entity."""
    raise NotImplementedError

  def bbox(self):
    """Return a bounding box for this entity."""
    c = self.point()
    return [c[0], c[1], c[0], c[1]]

  # Load from GTFS or from JSON.
  @classmethod
  def from_gtfs(cls, feed, debug=False):
    raise NotImplementedError

  @classmethod
  def from_json(cls, data):
    return cls(**data)

  def json(self):
    """Return a GeoJSON representation of this entity."""
    raise NotImplementedError

  def json_datastore(self, rels=True):
    """Return a GeoJSON representation for the Transitland Datastore."""
    # Todo: Longer discussion on formats...
    data = self.json()
    skip = ['features']
    if not rels:
      skip += [
        'serves',
        'doesNotServe',
        'servedBy',
        'notServedBy',
        # 'operatedBy' # required!
      ]
    for key in skip:
      data.pop(key, None)
    return data

  # Tags and identifiers
  def tags(self):
    if 'tags' not in self.data:
      self.data['tags'] = {}
    return self.data.get('tags')

  def identifiers(self):
    return self.data.get('identifiers') or []

  def set_tag(self, key, value):
    self.add_tags({key:value})

  def add_tags(self, tags):
    if 'tags' not in self.data:
      self.data['tags'] = {}
    self.data['tags'].update(tags)

  def add_identifier(self, identifier):
    """Add GTFS data to the set of identifiers."""
    if 'identifiers' not in self.data:
      self.data['identifiers'] = []
    if identifier in self.data['identifiers']:
      raise errors.ExistingIdentifierError(
        "Identifier already present: %s"%identifier
      )
    self.data['identifiers'].append(identifier)

  # Rename
  def merge(self, item, ignore_existing=True):
    """Merge data into identifiers."""
    for identifier in item.identifiers():
      try:
        self.add_identifier(identifier)
      except errors.ExistingIdentifierError, e:
        if ignore_existing:
          pass
        else:
          raise
    # merge name and geometry.
    if 'name' in item.data:
      self.data['name'] = item.data['name']
    if 'geometry' in item.data:
      self.data['geometry'] = item.data['geometry']
    # merge tags
    for k,v in item.tags().items():
      self.set_tag(k,v)
    # merge relations
    relkeys = ['serves', 'servedBy', 'operatedBy', 'operatorsInFeed']
    for relkey in relkeys:
      if (relkey in self.data) or (relkey in item.data):
        a = set(self.data.get(relkey, []))
        b = set(item.data.get(relkey, []))
        self.data[relkey] = sorted(a | b)

  # Graph.
  def pclink(self, parent, child):
    """Create a parent-child relationship."""
    parent.children.add(child)
    child.parents.add(parent)

  # ... children
  def add_child(self, child):
    """Add a child relationship."""
    self.pclink(self, child)

  # ... parents
  def add_parent(self, parent):
    """Add a parent relationship."""
    self.pclink(parent, self)
    <commit_msg>Fix bug with tags = None<commit_after>"""Base Transitland Entity."""
import json

import mzgeohash

import geom
import util
import errors

class Entity(object):
  """A Transitland Entity."""
  # OnestopID prefix.
  onestop_type = None

  def __init__(self, **data):
    """Set name, Onestop ID, and geometry."""
    if 'onestop_id' in data:
      data['onestopId'] = data.pop('onestop_id')
    self.data = data
    self.parents = set()
    self.children = set()

  # Basic ID, name, geometry...
  def name(self):
    """A reasonable display name for the entity."""
    return self.data.get('name')

  def id(self):
    """Alias to onestop()"""
    return self.onestop()

  def onestop(self):
    """Return the Onestop ID for this entity."""
    return self.data.get('onestopId') or self.make_onestop()

  def make_onestop(self):
    # Check maximum length.
    onestop = '%s-%s-%s'%(
      self.onestop_type,
      self.geohash()[:util.GEOHASH_LENGTH],
      self.mangle(self.name())
    )
    return onestop[:util.ONESTOP_LENGTH]

  def mangle(self, s):
    """Mangle a string into a Onestop component."""
    s = s.lower()
    for a,b in util.REPLACE_CHAR:
      s = a.sub(b,s)
    return s

  # Entity geometry.
  def geohash(self):
    """Return the geohash for this entity."""
    raise NotImplementedError

  def geometry(self):
    """Return a GeoJSON-type geometry for this entity."""
    # TODO: Right now, this has to be supplied by GTFS Entity...
    return self.data.get('geometry')

  def point(self):
    """Return a point for this entity."""
    raise NotImplementedError

  def bbox(self):
    """Return a bounding box for this entity."""
    c = self.point()
    return [c[0], c[1], c[0], c[1]]

  # Load from GTFS or from JSON.
  @classmethod
  def from_gtfs(cls, feed, debug=False):
    raise NotImplementedError

  @classmethod
  def from_json(cls, data):
    return cls(**data)

  def json(self):
    """Return a GeoJSON representation of this entity."""
    raise NotImplementedError

  def json_datastore(self, rels=True):
    """Return a GeoJSON representation for the Transitland Datastore."""
    # Todo: Longer discussion on formats...
    data = self.json()
    skip = ['features']
    if not rels:
      skip += [
        'serves',
        'doesNotServe',
        'servedBy',
        'notServedBy',
        # 'operatedBy' # required!
      ]
    for key in skip:
      data.pop(key, None)
    return data

  # Tags and identifiers
  def tags(self):
    if not self.data.get('tags'):
      self.data['tags'] = {}
    return self.data.get('tags')

  def identifiers(self):
    return self.data.get('identifiers') or []

  def set_tag(self, key, value):
    self.add_tags({key:value})

  def add_tags(self, tags):
    if not self.data.get('tags'):
      self.data['tags'] = {}
    self.data['tags'].update(tags)

  def add_identifier(self, identifier):
    """Add GTFS data to the set of identifiers."""
    if not self.data.get('identifiers'):
      self.data['identifiers'] = []
    if identifier in self.data['identifiers']:
      raise errors.ExistingIdentifierError(
        "Identifier already present: %s"%identifier
      )
    self.data['identifiers'].append(identifier)

  # Rename
  def merge(self, item, ignore_existing=True):
    """Merge data into identifiers."""
    for identifier in item.identifiers():
      try:
        self.add_identifier(identifier)
      except errors.ExistingIdentifierError, e:
        if ignore_existing:
          pass
        else:
          raise
    # merge name and geometry.
    if 'name' in item.data:
      self.data['name'] = item.data['name']
    if 'geometry' in item.data:
      self.data['geometry'] = item.data['geometry']
    # merge tags
    for k,v in item.tags().items():
      self.set_tag(k,v)
    # merge relations
    relkeys = ['serves', 'servedBy', 'operatedBy', 'operatorsInFeed']
    for relkey in relkeys:
      if (relkey in self.data) or (relkey in item.data):
        a = set(self.data.get(relkey, []))
        b = set(item.data.get(relkey, []))
        self.data[relkey] = sorted(a | b)

  # Graph.
  def pclink(self, parent, child):
    """Create a parent-child relationship."""
    parent.children.add(child)
    child.parents.add(parent)

  # ... children
  def add_child(self, child):
    """Add a child relationship."""
    self.pclink(self, child)

  # ... parents
  def add_parent(self, parent):
    """Add a parent relationship."""
    self.pclink(parent, self)
    <|endoftext|>