<commit_before>#!/bin/python2.7
"""
A tool to insert institutions from CSV files.

Requirements:
 - requests
 - gusregon
 - unicodecsv
 - tqdm

Example usage:

To run help text use:
$ python insert_institution_generic.py -h
"""

import argparse
import sys

import requests
import csv
from gusregon import GUS

from utils import environ
from insert_institution import normalize_jst

from urllib.parse import urljoin

class ScriptError(Exception):
    pass

class Command:
    REQUIRED_FIELDS = ["name", "email", "regon", "tags"]
    FIELDS_MAP = {
        # Fields which are processed with their alternate names
        "obj_id": "Id",
        "name": "Nazwa",
        "email": "Adres e-mail instytucji",
        "regon": "Kod REGON",
        "jst": "JST id",
        "tags": "Nazwy tagów",
    }

    def __init__(self, argv):
        self.argv = argv
        self.args = self.get_build_args(argv[1:])

        if self.args.gusregon_sandbox:
            sys.stderr.write(
                "You are using sandbox mode for the REGON database. "
                "Data may be incorrect. "
            )

        self.gus = GUS(
            api_key=(
                self.args.gusregon_api_key
                or environ("GUSREGON_API_KEY", required=False)
            ),
            sandbox=self.args.gusregon_sandbox,
        )
        self.s = requests.Session()
        self.s.auth = (self.args.user, self.args.password)
        self.done_count = 0
        self.total_count = None
        self.tags = self._get_tags()

    def get_build_args(self, argv):
        parser = argparse.ArgumentParser()
        parser.add_argument(
            "--input", required=True, type=argparse.FileType("r"), help="Input CSV-file"
        )
        parser.add_argument("--host", required=True, help="Host of instance")
        parser.add_argument("--user", required=True, help="User to authentication")
        parser.add_argument(
            "--password", required=True, help="Password to authentication"
        )
        parser.add_argument(
            "--gusregon-sandbox",
            required=False,
            help="GUS REGON sandbox mode (no API key needed)",
            dest="gusregon_sandbox",
            action="store_true",
            default=False,
        )
        parser.add_argument(
            "--gusregon-api-key",
            required=False,
            help="GUS REGON API KEY",
            dest="gusregon_api_key",
            action="store",
            default=None,
        )
        parser.add_argument(
            "--name-exact",
            required=False,
            help="Do institution name should match exact GUS data name?",
            dest="name_exact",
            action="store_true",
            default=False,
        )
        parser.add_argument(
            "--name-prefix",
            required=False,
            help="Prefix of the institution name which is expected to be the same",
            dest="name_prefix",
            action="store",
            default="",
        )
        parser.add_argument(
            "--name-suffix-field",
            required=False,
            help="In what field of GUS REGON data should institution suffix "
            "be looked for",
            dest="name_suffix_field",
            action="store",
            default=None,
        )
        parser.add_argument(
            "--simulate",
            required=False,
            help="Do not insert any data",
            dest="simulate",
            action="store_true",
            default=False,
        )
        parser.add_argument(
            "--explicit",
            required=False,
            help="Prints detailed data of the institution if GUS data "
            "validation fails.",
            dest="explicit",
            action="store_true",
            default=False,
        )
        parser.add_argument(
            "--create-missing-tags",
            required=False,
            help="Creates nonexistent tags, if not set the script will be stopped "
            "after failed attempt of finding tag with given name.",
            dest="create_tags",
            action="store_true",
            default=False,
        )
        return parser.parse_args(argv)

    def _match(self, host, **query):
        response = self.s.get(url=urljoin(host, "/api/institutions/"), params=query)
        data = response.json()
        return data["results"][0]["pk"] if data["results"] else None

    def _get_tags(self):
        response = self.s.get(
            url=urljoin(self.args.host, "/api/tags/"), params={"page_size": 10000}
        )
        data = response.json()
        return data["results"]

    def _find_tag(self, name):
        for tag in self.tags:
            if tag["name"] == name:
                return tag
        return None

    def _print_gus_data(self, name, gus_data):
        print('GUS data for institution "{}":'.format(name))
        for key, val in gus_data.items():
            if val:
                print(" - {}: {}".format(key, val))
        print()

    def _normalize_row(self, **data):
        def _get_val(f_name):
            return (
                data.get(f_name) or data.get(self.FIELDS_MAP[f_name])
                if f_name in self.FIELDS_MAP
                else None
            )

        mapped = {}
        for field_name in self.FIELDS_MAP.keys():
            mapped[field_name] = _get_val(field_name)

        tag_names = [tag.strip() for tag in mapped["tags"].split("|")]
        mapped["tags"] = []

        for tag_name in tag_names:
            tag = self._find_tag(tag_name)
            if tag:
                mapped["tags"].append(tag["name"])
            else:
                print('Warning! Found nonexistent tag named "{}".'.format(tag_name))

                if not self.args.create_tags:
                    raise ScriptError(
                        'Missing tag named "{}" with --create-tags flag turned off. '
                        "The script will be terminated.".format(tag_name),
                    )
                else:
                    mapped["tags"].append(tag_name)

        return mapped

    def _get_and_validate_regon_data(self, data):
        regon_data = self.gus.search(regon=data["regon"])

        if not regon_data:
            raise ScriptError(
                'Regon {} for institution "{}" has not been found '
                "in GUS database.".format(data["regon"], data["name"])
            )

        regon_data_name = regon_data.get("nazwa", "?").upper()

        if self.args.name_exact and data["name"].upper() != regon_data_name:
            print(
                'Warning! GUS name "{}" does not match '
                'institution name "{}"'.format(regon_data_name, data["name"].upper())
            )
            if self.args.explicit:
                self._print_gus_data(data["name"], regon_data)

        if (
            self.args.name_prefix
            and self.args.name_prefix.upper() not in regon_data_name
        ):
            print(
                'Warning! GUS name "{}" does not contain '
                'expected prefix "{}".'.format(
                    regon_data_name, self.args.name_prefix.upper()
                )
            )
            if self.args.explicit:
                self._print_gus_data(data["name"], regon_data)

        # this is dynamic name part after removing constant prefix
        expected_suffix = (
            data["name"].upper().replace(self.args.name_prefix.upper(), "").strip()
        )
        regon_suffix = regon_data.get(self.args.name_suffix_field, "").upper()

        if self.args.name_suffix_field and expected_suffix not in regon_suffix:
            print(
                'Warning! GUS field "{}" does not contain '
                'expected value "{}" but "{}".'.format(
                    self.args.name_suffix_field, expected_suffix, regon_suffix
                )
            )
            if self.args.explicit:
                self._print_gus_data(data["name"], regon_data)

        return regon_data

    def _get_terc(self, data, extra, jst, regon_data):
        if "terc" in extra:
            terc = extra.get("terc")

        elif regon_data:
            terc = "".join(
                [
                    regon_data["adsiedzwojewodztwo_symbol"],
                    regon_data["adsiedzpowiat_symbol"],
                    regon_data["adsiedzgmina_symbol"],
                ]
            )
            if normalize_jst(jst) != normalize_jst(terc):
                print(
                    'Warning! Row JST: "{}" differs from GUS JST: "{}" '
                    'for institution "{}"'.format(jst, terc, data["name"])
                )
                if self.args.explicit:
                    self._print_gus_data(data["name"], regon_data)

        elif jst:
            terc = jst

        else:
            raise ScriptError("Missing terc and unable to find.", data["name"])

        return terc

    def _handle_api_response(self, response, data, progress):
        json = response.json()
        if response.status_code == 201:
            print(
                '{:6.2f}%: "{}" created as PK {}'.format(
                    progress, data["name"], json["pk"]
                )
            )
        elif response.status_code == 200:
            print(
                '{:6.2f}%: "{}" updated as PK {}'.format(
                    progress, data["name"], json["pk"]
                )
            )
        else:
            print(
                '{:6.2f}%: "{}" Response status code: {}.'.format(
                    progress, data["name"], response.status_code
                ),
                file=sys.stderr,
            )
            print(json, file=sys.stderr)

    def _push_to_api(self, data, regon_data, obj_id):
        response = None

        if obj_id:
            pk = obj_id
        elif data["regon"]:
            pk = self._match(self.args.host, regon=data["regon"])
        else:
            pk = None

        if pk:
            data.update({"id": pk})
            if not self.args.simulate:
                response = self.s.patch(
                    url=urljoin(self.args.host, "/api/institutions/{}/".format(pk)),
                    json=data,
                )
            else:
                print('Simulated PATCH for "{}"\n'.format(data["name"]))

        else:
            if not self.args.simulate:
                response = self.s.post(
                    url=urljoin(self.args.host, "/api/institutions/"), json=data
                )
            else:
                print('Simulated POST for "{}"\n'.format(data["name"]))

        if response is not None and response.status_code >= 300:
            error_msg = 'Error! Institution: "{}" got response status: {}.'.format(
                data["name"], response.status_code
            )
            print(error_msg, file=sys.stderr)
            print(response.text, file=sys.stderr)
            if self.args.explicit:
                self._print_gus_data(data["name"], regon_data)
            raise ScriptError(error_msg)

        self.done_count += 1
        progress = (self.done_count / self.total_count) * 100

        if response:
            self._handle_api_response(response, data, progress)

    def insert_row(self, host, obj_id, name, email, regon, jst, tags, **extra):
        data = {"name": name, "email": email, "tags": tags}

        if regon:
            regon = regon.strip(".").strip().rjust(9, "0")
            data["regon"] = regon
            regon_data = self._get_and_validate_regon_data(data)
        else:
            regon_data = None

        terc = self._get_terc(data, extra, jst, regon_data)
        data["jst"] = normalize_jst(terc)

        if regon_data:
            data["extra"] = {"regon": regon_data}

        regon_parent = extra.get("regon_parent")
        if regon_parent:
            matched_parent = [self._match(host, regon=regon_parent)]
            if matched_parent is None:
                raise ScriptError(
                    "Parent institution with REGON {} not found".format(regon_parent)
                )
            data["parents_ids"] = [matched_parent]

        self._push_to_api(data, regon_data, obj_id)

    def fields_validation(self, fields):
        recog_fields = []
        for field in fields:
            if field in self.REQUIRED_FIELDS or field in self.FIELDS_MAP.values():
                recog_fields.append(field)

        result = True
        for req_field in self.REQUIRED_FIELDS:
            if req_field not in fields and self.FIELDS_MAP.get(req_field) not in fields:
                alt_name = ""
                for key, val in self.FIELDS_MAP.items():
                    if val == req_field:
                        alt_name += ' or "{}"'.format(key)
                print(
                    "There is missing column in the input file. "
                    'Required field\'s name is "{}"{}'.format(req_field, alt_name),
                    file=sys.stderr,
                )
                result = False
        return result

    def run(self):
        reader = csv.DictReader(self.args.input)

        if not self.fields_validation(reader.fieldnames):
            print("Script stop, due previos erros.", file=sys.stderr)
            return 5

        data = list(reader)
        self.total_count = len(data)
        for row in data:
            normalized_row = self._normalize_row(**row)
            self.insert_row(host=self.args.host, **normalized_row)

if __name__ == "__main__":
    sys.exit(Command(sys.argv).run())
<commit_msg>jst not required in the input file.<commit_after>#!/bin/python
"""
A tool to insert institutions from CSV files.

Requirements:
 - requests
 - gusregon
 - unicodecsv
 - tqdm

Example usage:

To run help text use:
$ python insert_institution_generic.py -h
"""

import argparse
import sys

import requests
import csv
from gusregon import GUS

from utils import environ
from insert_institution import normalize_jst

from urllib.parse import urljoin

class ScriptError(Exception):
    pass

class Command:
    REQUIRED_FIELDS = ["name", "email", "regon", "tags"]
    FIELDS_MAP = {
        # Fields which are processed with their alternate names
        "obj_id": "Id",
        "name": "Nazwa",
        "email": "Adres e-mail instytucji",
        "regon": "Kod REGON",
        "jst": "JST id",
        "tags": "Nazwy tagów",
    }

    def __init__(self, argv):
        self.argv = argv
        self.args = self.get_build_args(argv[1:])

        if self.args.gusregon_sandbox:
            sys.stderr.write(
                "You are using sandbox mode for the REGON database. "
                "Data may be incorrect. "
            )

        self.gus = GUS(
            api_key=(
                self.args.gusregon_api_key
                or environ("GUSREGON_API_KEY", required=False)
            ),
            sandbox=self.args.gusregon_sandbox,
        )
        self.s = requests.Session()
        self.s.auth = (self.args.user, self.args.password)
        self.done_count = 0
        self.total_count = None
        self.tags = self._get_tags()

    def get_build_args(self, argv):
        parser = argparse.ArgumentParser()
        parser.add_argument(
            "--input", required=True, type=argparse.FileType("r"), help="Input CSV-file"
        )
        parser.add_argument("--host", required=True, help="Host of instance")
        parser.add_argument("--user", required=True, help="User to authentication")
        parser.add_argument(
            "--password", required=True, help="Password to authentication"
        )
        parser.add_argument(
            "--gusregon-sandbox",
            required=False,
            help="GUS REGON sandbox mode (no API key needed)",
            dest="gusregon_sandbox",
            action="store_true",
            default=False,
        )
        parser.add_argument(
            "--gusregon-api-key",
            required=False,
            help="GUS REGON API KEY",
            dest="gusregon_api_key",
            action="store",
            default=None,
        )
        parser.add_argument(
            "--name-exact",
            required=False,
            help="Do institution name should match exact GUS data name?",
            dest="name_exact",
            action="store_true",
            default=False,
        )
        parser.add_argument(
            "--name-prefix",
            required=False,
            help="Prefix of the institution name which is expected to be the same",
            dest="name_prefix",
            action="store",
            default="",
        )
        parser.add_argument(
            "--name-suffix-field",
            required=False,
            help="In what field of GUS REGON data should institution suffix "
            "be looked for",
            dest="name_suffix_field",
            action="store",
            default=None,
        )
        parser.add_argument(
            "--simulate",
            required=False,
            help="Do not insert any data",
            dest="simulate",
            action="store_true",
            default=False,
        )
        parser.add_argument(
            "--explicit",
            required=False,
            help="Prints detailed data of the institution if GUS data "
            "validation fails.",
            dest="explicit",
            action="store_true",
            default=False,
        )
        parser.add_argument(
            "--create-missing-tags",
            required=False,
            help="Creates nonexistent tags, if not set the script will be stopped "
            "after failed attempt of finding tag with given name.",
            dest="create_tags",
            action="store_true",
            default=False,
        )
        return parser.parse_args(argv)

    def _match(self, host, **query):
        response = self.s.get(url=urljoin(host, "/api/institutions/"), params=query)
        data = response.json()
        return data["results"][0]["pk"] if data["results"] else None

    def _get_tags(self):
        response = self.s.get(
            url=urljoin(self.args.host, "/api/tags/"), params={"page_size": 10000}
        )
        data = response.json()
        return data["results"]

    def _find_tag(self, name):
        for tag in self.tags:
            if tag["name"] == name:
                return tag
        return None

    def _print_gus_data(self, name, gus_data):
        print('GUS data for institution "{}":'.format(name))
        for key, val in gus_data.items():
            if val:
                print(" - {}: {}".format(key, val))
        print()

    def _normalize_row(self, **data):
        def _get_val(f_name):
            return (
                data.get(f_name) or data.get(self.FIELDS_MAP[f_name])
                if f_name in self.FIELDS_MAP
                else None
            )

        mapped = {}
        for field_name in self.FIELDS_MAP.keys():
            mapped[field_name] = _get_val(field_name)

        tag_names = [tag.strip() for tag in mapped["tags"].split("|")]
        mapped["tags"] = []

        for tag_name in tag_names:
            tag = self._find_tag(tag_name)
            if tag:
                mapped["tags"].append(tag["name"])
            else:
                print('Warning! Found nonexistent tag named "{}".'.format(tag_name))

                if not self.args.create_tags:
                    raise ScriptError(
                        'Missing tag named "{}" with --create-tags flag turned off. '
                        "The script will be terminated.".format(tag_name),
                    )
                else:
                    mapped["tags"].append(tag_name)

        return mapped

    def _get_and_validate_regon_data(self, data):
        regon_data = self.gus.search(regon=data["regon"])

        if not regon_data:
            raise ScriptError(
                'Regon {} for institution "{}" has not been found '
                "in GUS database.".format(data["regon"], data["name"])
            )

        regon_data_name = regon_data.get("nazwa", "?").upper()

        if self.args.name_exact and data["name"].upper() != regon_data_name:
            print(
                'Warning! GUS name "{}" does not match '
                'institution name "{}"'.format(regon_data_name, data["name"].upper())
            )
            if self.args.explicit:
                self._print_gus_data(data["name"], regon_data)

        if (
            self.args.name_prefix
            and self.args.name_prefix.upper() not in regon_data_name
        ):
            print(
                'Warning! GUS name "{}" does not contain '
                'expected prefix "{}".'.format(
                    regon_data_name, self.args.name_prefix.upper()
                )
            )
            if self.args.explicit:
                self._print_gus_data(data["name"], regon_data)

        # this is dynamic name part after removing constant prefix
        expected_suffix = (
            data["name"].upper().replace(self.args.name_prefix.upper(), "").strip()
        )
        regon_suffix = regon_data.get(self.args.name_suffix_field, "").upper()

        if self.args.name_suffix_field and expected_suffix not in regon_suffix:
            print(
                'Warning! GUS field "{}" does not contain '
                'expected value "{}" but "{}".'.format(
                    self.args.name_suffix_field, expected_suffix, regon_suffix
                )
            )
            if self.args.explicit:
                self._print_gus_data(data["name"], regon_data)

        return regon_data

    def _get_terc(self, data, extra, jst, regon_data):
        if "terc" in extra:
            terc = extra.get("terc")

        elif regon_data:
            terc = "".join(
                [
                    regon_data["adsiedzwojewodztwo_symbol"],
                    regon_data["adsiedzpowiat_symbol"],
                    regon_data["adsiedzgmina_symbol"],
                ]
            )
            if jst and normalize_jst(jst) != normalize_jst(terc):
                print(
                    'Warning! Row JST: "{}" differs from GUS JST: "{}" '
                    'for institution "{}"'.format(jst, terc, data["name"])
                )
                if self.args.explicit:
                    self._print_gus_data(data["name"], regon_data)

        elif jst:
            terc = jst

        else:
            raise ScriptError("Missing terc and unable to find.", data["name"])

        return terc

    def _handle_api_response(self, response, data, progress):
        json = response.json()
        if response.status_code == 201:
            print(
                '{:6.2f}%: "{}" created as PK {}'.format(
                    progress, data["name"], json["pk"]
                )
            )
        elif response.status_code == 200:
            print(
                '{:6.2f}%: "{}" updated as PK {}'.format(
                    progress, data["name"], json["pk"]
                )
            )
        else:
            print(
                '{:6.2f}%: "{}" Response status code: {}.'.format(
                    progress, data["name"], response.status_code
                ),
                file=sys.stderr,
            )
            print(json, file=sys.stderr)

    def _push_to_api(self, data, regon_data, obj_id):
        response = None

        if obj_id:
            pk = obj_id
        elif data["regon"]:
            pk = self._match(self.args.host, regon=data["regon"])
        else:
            pk = None

        if pk:
            data.update({"id": pk})
            if not self.args.simulate:
                response = self.s.patch(
                    url=urljoin(self.args.host, "/api/institutions/{}/".format(pk)),
                    json=data,
                )
            else:
                print('Simulated PATCH for "{}"\n'.format(data["name"]))

        else:
            if not self.args.simulate:
                response = self.s.post(
                    url=urljoin(self.args.host, "/api/institutions/"), json=data
                )
            else:
                print('Simulated POST for "{}"\n'.format(data["name"]))

        if response is not None and response.status_code >= 300:
            error_msg = 'Error! Institution: "{}" got response status: {}.'.format(
                data["name"], response.status_code
            )
            print(error_msg, file=sys.stderr)
            print(response.text, file=sys.stderr)
            if self.args.explicit:
                self._print_gus_data(data["name"], regon_data)
            raise ScriptError(error_msg)

        self.done_count += 1
        progress = (self.done_count / self.total_count) * 100

        if response:
            self._handle_api_response(response, data, progress)

    def insert_row(self, host, obj_id, name, email, regon, jst, tags, **extra):
        data = {"name": name, "email": email, "tags": tags}

        if regon:
            regon = regon.strip(".").strip().rjust(9, "0")
            data["regon"] = regon
            regon_data = self._get_and_validate_regon_data(data)
        else:
            regon_data = None

        terc = self._get_terc(data, extra, jst, regon_data)
        data["jst"] = normalize_jst(terc)

        if regon_data:
            data["extra"] = {"regon": regon_data}

        regon_parent = extra.get("regon_parent")
        if regon_parent:
            matched_parent = [self._match(host, regon=regon_parent)]
            if matched_parent is None:
                raise ScriptError(
                    "Parent institution with REGON {} not found".format(regon_parent)
                )
            data["parents_ids"] = [matched_parent]

        self._push_to_api(data, regon_data, obj_id)

    def fields_validation(self, fields):
        recog_fields = []
        for field in fields:
            if field in self.REQUIRED_FIELDS or field in self.FIELDS_MAP.values():
                recog_fields.append(field)

        result = True
        for req_field in self.REQUIRED_FIELDS:
            if req_field not in fields and self.FIELDS_MAP.get(req_field) not in fields:
                alt_name = ""
                for key, val in self.FIELDS_MAP.items():
                    if val == req_field:
                        alt_name += ' or "{}"'.format(key)
                print(
                    "There is missing column in the input file. "
                    'Required field\'s name is "{}"{}'.format(req_field, alt_name),
                    file=sys.stderr,
                )
                result = False
        return result

    def run(self):
        reader = csv.DictReader(self.args.input)

        if not self.fields_validation(reader.fieldnames):
            print("Script stop, due previos erros.", file=sys.stderr)
            return 5

        data = list(reader)
        self.total_count = len(data)
        for row in data:
            normalized_row = self._normalize_row(**row)
            self.insert_row(host=self.args.host, **normalized_row)

if __name__ == "__main__":
    sys.exit(Command(sys.argv).run())
<|endoftext|>


<commit_before>from django.contrib import admin
from timepiece import models as timepiece

class ActivityAdmin(admin.ModelAdmin):
    model = timepiece.Activity
    list_display = ('code', 'name', 'billable')
    list_filter = ('billable',)
admin.site.register(timepiece.Activity, ActivityAdmin)

class HourGroupAdmin(admin.ModelAdmin):
    model = timepiece.HourGroup
    list_display = ('name',)
    list_filter = ('activities',)
    ordering = ('order', 'name')
admin.site.register(timepiece.HourGroup, HourGroupAdmin)

class ActivityGroupAdmin(admin.ModelAdmin):
    model = timepiece.ActivityGroup
    list_display = ('name',)
    list_filter = ('activities',)
admin.site.register(timepiece.ActivityGroup, ActivityGroupAdmin)

class RelationshipTypeAdmin(admin.ModelAdmin):
    pass
admin.site.register(timepiece.RelationshipType, RelationshipTypeAdmin)

class BusinessAdmin(admin.ModelAdmin):
    list_display = ['name', 'short_name']
    search_fields = ['name', 'short_name']
admin.site.register(timepiece.Business, BusinessAdmin)

class EntryAdmin(admin.ModelAdmin):
    model = timepiece.Entry
    list_display = ('user',
                    'project',
                    'location',
                    'project_type',
                    'activity',
                    'start_time',
                    'end_time',
                    'hours',
                    'is_closed',
                    'is_paused',
                    )
    list_filter = ['activity', 'project__type', 'user', 'project']
    search_fields = ['user__first_name', 'user__last_name', 'project__name',
                     'activity__name', 'comments']
    date_hierarchy = 'start_time'
    ordering = ('-start_time',)

    def project_type(self, entry):
        return entry.project.type
admin.site.register(timepiece.Entry, EntryAdmin)

class AttributeAdmin(admin.ModelAdmin):
    search_fields = ('label', 'type')
    list_display = ('label', 'type', 'enable_timetracking', 'billable')
    list_filter = ('type', 'enable_timetracking', 'billable')
    #Django honors only first field
    ordering = ('type', 'sort_order')
admin.site.register(timepiece.Attribute, AttributeAdmin)

class ContractAssignmentInline(admin.TabularInline):
    model = timepiece.ContractAssignment
    raw_id_fields = ('user',)

    def queryset(self, request):
        qs = super(ContractAssignmentInline, self).queryset(request)
        return qs.select_related()

class ContractMilestoneInline(admin.TabularInline):
    model = timepiece.ContractMilestone

class ProjectContractAdmin(admin.ModelAdmin):
    model = timepiece.ProjectContract
    list_display = ('_project', 'start_date', 'end_date', 'status',
                    'num_hours', 'hours_assigned', 'hours_unassigned',
                    'hours_worked')
    ordering = ('-end_date',)
    inlines = (ContractAssignmentInline, ContractMilestoneInline)
    list_filter = ('status',)
    raw_id_fields = ('project',)
    list_per_page = 20

    def _project(self, obj):
        return obj.project
    _project.admin_order_field = 'project__name'
    _project.short_description = 'Project'

    def hours_unassigned(self, obj):
        return obj.num_hours - obj.hours_assigned

admin.site.register(timepiece.ProjectContract, ProjectContractAdmin)

class ProjectContractInline(admin.TabularInline):
    model = timepiece.ProjectContract
    extra = 0

class ProjectAdmin(admin.ModelAdmin):
    model = timepiece.Project
    raw_id_fields = ('business',)
    list_display = ('name', 'business', 'point_person', 'status', 'type',)
    list_filter = ('type', 'status')
    inlines = (ProjectContractInline,)
    search_fields = ('name', 'business__name', 'point_person__username',
            'point_person__first_name', 'point_person__last_name',
            'description')
admin.site.register(timepiece.Project, ProjectAdmin)

class ContractAssignmentAdmin(admin.ModelAdmin):
    list_display = ('id', 'contract', 'user', 'start_date',
                    'end_date', 'min_hours_per_week', 'num_hours', 'worked',
                    'remaining')
    list_filter = ('contract',)
    ordering = ('-start_date',)

    def queryset(self, request):
        qs = super(ContractAssignmentAdmin, self).queryset(request)
        return qs.exclude(contract__status='complete')

    def worked(self, obj):
        hours_worked = float(obj.hours_worked)
        if obj.num_hours:
            percent = hours_worked * 100.0 / float(obj.num_hours)
            return "%.2f (%.2f%%)" % (hours_worked, percent)
        return ""

    def remaining(self, obj):
        return "%.2f" % (obj.hours_remaining,)

admin.site.register(timepiece.ContractAssignment, ContractAssignmentAdmin)

class LocationAdmin(admin.ModelAdmin):
    list_display = ('id', 'name')
admin.site.register(timepiece.Location, LocationAdmin)

class ProjectHoursAdmin(admin.ModelAdmin):
    list_display = ('_person', 'project', 'week_start', 'hours', 'published')

    def _person(self, obj):
        return obj.user.get_full_name()
    _person.short_description = 'Person'
    _person.admin_order_field = 'user__last_name'

admin.site.register(timepiece.ProjectHours, ProjectHoursAdmin)

class UserProfileAdmin(admin.ModelAdmin):
    list_display = ('user', 'hours_per_week')
admin.site.register(timepiece.UserProfile, UserProfileAdmin)
<commit_msg>Used horizontal filter for ManyToMany fields in admin<commit_after>from django.contrib import admin
from timepiece import models as timepiece

class ActivityAdmin(admin.ModelAdmin):
    model = timepiece.Activity
    list_display = ('code', 'name', 'billable')
    list_filter = ('billable',)
admin.site.register(timepiece.Activity, ActivityAdmin)

class HourGroupAdmin(admin.ModelAdmin):
    model = timepiece.HourGroup
    list_display = ('name',)
    list_filter = ('activities',)
    ordering = ('order', 'name')
    filter_horizontal = ('activities',)
admin.site.register(timepiece.HourGroup, HourGroupAdmin)

class ActivityGroupAdmin(admin.ModelAdmin):
    model = timepiece.ActivityGroup
    list_display = ('name',)
    list_filter = ('activities',)
    filter_horizontal = ('activities',)
admin.site.register(timepiece.ActivityGroup, ActivityGroupAdmin)

class RelationshipTypeAdmin(admin.ModelAdmin):
    pass
admin.site.register(timepiece.RelationshipType, RelationshipTypeAdmin)

class BusinessAdmin(admin.ModelAdmin):
    list_display = ['name', 'short_name']
    search_fields = ['name', 'short_name']
admin.site.register(timepiece.Business, BusinessAdmin)

class EntryAdmin(admin.ModelAdmin):
    model = timepiece.Entry
    list_display = ('user',
                    'project',
                    'location',
                    'project_type',
                    'activity',
                    'start_time',
                    'end_time',
                    'hours',
                    'is_closed',
                    'is_paused',
                    )
    list_filter = ['activity', 'project__type', 'user', 'project']
    search_fields = ['user__first_name', 'user__last_name', 'project__name',
                     'activity__name', 'comments']
    date_hierarchy = 'start_time'
    ordering = ('-start_time',)

    def project_type(self, entry):
        return entry.project.type
admin.site.register(timepiece.Entry, EntryAdmin)

class AttributeAdmin(admin.ModelAdmin):
    search_fields = ('label', 'type')
    list_display = ('label', 'type', 'enable_timetracking', 'billable')
    list_filter = ('type', 'enable_timetracking', 'billable')
    #Django honors only first field
    ordering = ('type', 'sort_order')
admin.site.register(timepiece.Attribute, AttributeAdmin)

class ContractAssignmentInline(admin.TabularInline):
    model = timepiece.ContractAssignment
    raw_id_fields = ('user',)

    def queryset(self, request):
        qs = super(ContractAssignmentInline, self).queryset(request)
        return qs.select_related()

class ContractMilestoneInline(admin.TabularInline):
    model = timepiece.ContractMilestone

class ProjectContractAdmin(admin.ModelAdmin):
    model = timepiece.ProjectContract
    list_display = ('_project', 'start_date', 'end_date', 'status',
                    'num_hours', 'hours_assigned', 'hours_unassigned',
                    'hours_worked')
    ordering = ('-end_date',)
    inlines = (ContractAssignmentInline, ContractMilestoneInline)
    list_filter = ('status',)
    raw_id_fields = ('project',)
    list_per_page = 20

    def _project(self, obj):
        return obj.project
    _project.admin_order_field = 'project__name'
    _project.short_description = 'Project'

    def hours_unassigned(self, obj):
        return obj.num_hours - obj.hours_assigned

admin.site.register(timepiece.ProjectContract, ProjectContractAdmin)

class ProjectContractInline(admin.TabularInline):
    model = timepiece.ProjectContract
    extra = 0

class ProjectAdmin(admin.ModelAdmin):
    model = timepiece.Project
    raw_id_fields = ('business',)
    list_display = ('name', 'business', 'point_person', 'status', 'type',)
    list_filter = ('type', 'status')
    inlines = (ProjectContractInline,)
    search_fields = ('name', 'business__name', 'point_person__username',
            'point_person__first_name', 'point_person__last_name',
            'description')
admin.site.register(timepiece.Project, ProjectAdmin)

class ContractAssignmentAdmin(admin.ModelAdmin):
    list_display = ('id', 'contract', 'user', 'start_date',
                    'end_date', 'min_hours_per_week', 'num_hours', 'worked',
                    'remaining')
    list_filter = ('contract',)
    ordering = ('-start_date',)

    def queryset(self, request):
        qs = super(ContractAssignmentAdmin, self).queryset(request)
        return qs.exclude(contract__status='complete')

    def worked(self, obj):
        hours_worked = float(obj.hours_worked)
        if obj.num_hours:
            percent = hours_worked * 100.0 / float(obj.num_hours)
            return "%.2f (%.2f%%)" % (hours_worked, percent)
        return ""

    def remaining(self, obj):
        return "%.2f" % (obj.hours_remaining,)

admin.site.register(timepiece.ContractAssignment, ContractAssignmentAdmin)

class LocationAdmin(admin.ModelAdmin):
    list_display = ('id', 'name')
admin.site.register(timepiece.Location, LocationAdmin)

class ProjectHoursAdmin(admin.ModelAdmin):
    list_display = ('_person', 'project', 'week_start', 'hours', 'published')

    def _person(self, obj):
        return obj.user.get_full_name()
    _person.short_description = 'Person'
    _person.admin_order_field = 'user__last_name'

admin.site.register(timepiece.ProjectHours, ProjectHoursAdmin)

class UserProfileAdmin(admin.ModelAdmin):
    list_display = ('user', 'hours_per_week')
admin.site.register(timepiece.UserProfile, UserProfileAdmin)
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-

import timeside, os, uuid, time, hashlib, mimetypes

from timeside.analyzer.core import AnalyzerResultContainer, AnalyzerResult

from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.contrib.auth.models import User

from jsonfield import JSONField

app = 'timeside'

processors = timeside.core.processors(timeside.api.IProcessor)

PROCESSOR_PIDS = [(processor.id(), processor.id())  for processor in processors]

PROCESSOR_TYPES = (('decoder', _('decoder')), ('analyzer', _('analyzer')),
                   ('grapher', _('grapher')), ('encoder', _('encoder')))

STATUS = ((0, _('failed')), (1, _('pending')), (2, _('running')),
                         (3, _('done')), (4, _('ready')))

def get_mime_type(path):
    return mimetypes.guess_type(path)[0]

def get_processor(pid):
    for proc in processors:
        if proc.id == pid:
            return proc()
    raise ValueError('Processor %s does not exists' % pid)

class MetaCore:

    app_label = app

class BaseResource(models.Model):

    date_added = models.DateTimeField(_('date added'), auto_now_add=True)
    date_modified = models.DateTimeField(_('date modified'), auto_now=True, null=True)
    uuid = models.CharField(_('uuid'), blank=True, max_length=512, )

    class Meta(MetaCore):
        abstract = True

    def save(self, **kwargs):
        if not self.uuid:
            self.uuid = uuid.uuid4()
        super(BaseResource, self).save(**kwargs)

class DocumentedBaseResource(BaseResource):

    title = models.CharField(_('title'), blank=True, max_length=512)
    description = models.TextField(_('description'), blank=True)

    def __unicode__(self):
        return self.title

    class Meta(MetaCore):
        abstract = True

class Collection(DocumentedBaseResource):

    items = models.ManyToManyField('Item', related_name="collections", verbose_name=_('items'), blank=True, null=True)

    class Meta(MetaCore):
        db_table = app + '_collections'
        ordering = ['title']
        verbose_name = _('collection')

class Item(DocumentedBaseResource):

    file = models.FileField(_('file'), upload_to='items/%Y/%m/%d', blank=True, max_length=1024)
    url = models.URLField(_('URL'), blank=True, max_length=1024)
    sha1 = models.CharField(_('sha1'), unique=True, blank=True, max_length=512)
    mime_type = models.CharField(_('mime type'), blank=True, max_length=256)
    hdf5 = models.FileField(_('HDF5 result file'), upload_to='items/%Y/%m/%d', blank=True, max_length=1024)
    lock = models.BooleanField(default=False)

    class Meta(MetaCore):
        db_table = app + '_items'
        ordering = ['title']
        verbose_name = _('item')

    def save(self, **kwargs):
        if self.file:
            self.mime_type = get_mime_type(self.file.path)
        if not self.sha1:
            pass
        super(Item, self).save(**kwargs)

    def results(self):
        return [result for result in self.results.all()]

class Experience(DocumentedBaseResource):

    processors = models.ManyToManyField('Processor', related_name="experiences", verbose_name=_('processors'), blank=True, null=True)
    author = models.ForeignKey(User, related_name="experiences", verbose_name=_('author'), blank=True, null=True, on_delete=models.SET_NULL)

    class Meta(MetaCore):
        db_table = app + '_experiences'
        verbose_name = _('Experience')

class Processor(BaseResource):

    pid = models.CharField(_('pid'), choices=PROCESSOR_PIDS, max_length=256)
    type = models.CharField(_('type'), choices=PROCESSOR_TYPES, default='none', max_length=64)
    parameters = JSONField(_('parameters'), blank=True, null=True)
    version = models.CharField(_('version'), max_length=64, blank=True)

    class Meta(MetaCore):
        db_table = app + '_processors'
        verbose_name = _('processor')

    def __unicode__(self):
        return '_'.join([self.type, self.pid, str(self.id)])

    def save(self, **kwargs):
        if not self.version:
            self.version = timeside.__version__
        super(Processor, self).save(**kwargs)

class Result(BaseResource):

    item = models.ForeignKey('Item', related_name="results", verbose_name=_('item'), blank=True, null=True, on_delete=models.SET_NULL)
    processor = models.ForeignKey('Processor', related_name="results", verbose_name=_('processor'), blank=True, null=True, on_delete=models.SET_NULL)
    json = JSONField(_('JSON result'), blank=True)
    hdf5 = models.FileField(_('HDF5 result file'), upload_to='results/%Y/%m/%d', blank=True, max_length=1024)
    output = models.FileField(_('Output file'), upload_to='results/%Y/%m/%d', blank=True, max_length=1024)
    output_mime_type = models.CharField(_('Output mime type'), blank=True, max_length=256)

    class Meta(MetaCore):
        db_table = app + '_results'
        verbose_name = _('Result')
        verbose_name_plural = _('Results')

    def __unicode__(self):
        return '_'.join([self.item.title, unicode(self.processor)])

    def save(self, **kwargs):
        if self.output:
            self.output_mime_type = get_mime_type(self.output.path)
        super(Result, self).save(**kwargs)

class Task(models.Model):

    experience = models.ForeignKey('Experience', related_name="task", verbose_name=_('experience'), blank=True, null=True)
    items = models.ManyToManyField('Item', related_name="task", verbose_name=_('items'), blank=True, null=True)
    status = models.IntegerField(_('status'), choices=STATUS, default=1)

    class Meta(MetaCore):
        db_table = app + '_tasks'
        verbose_name = _('Task')
        verbose_name_plural = _('Tasks')

    def __unicode__(self):
        return '_'.join([unicode(self.experience), unicode(self.id)])

    def status_setter(self, status):
        self.status = status
        self.save()

    def run(self):
        for item in self.items:
            pipe = timeside.decoder.FileDecoder(item.file)
            proc_dict = {}
            for processor in self.experience.processors.all():
                proc = get_processor(processor.id)
                #TODO: add parameters
                proc_dict[processor] = proc
                pipe = pipe | proc

            while item.lock:
                time.sleep(30)

            path = settings.MEDIA_ROOT + 'results' + os.sep + item.uuid + os.sep
            if not item.hdf5:
                item.hdf5 =  path + item.uuid + '.hdf5'
                item.save()

            try:
                self.status_setter(2)
                pipe.run()
                pipe.results.to_hdf5(item.hdf5)
            except:
                self.status_setter(0)

            if sef.status == 2:
                for processor in proc_dict.keys():
                    proc = proc_dict[processor]
                    results = Result.objects.filter(processor=processor, uuid=proc.UUID)
                    if not results:
                        result = Result(processor=processor, uuid=proc.UUID, item=item)
                    else:
                        result = results[0]
                    result.hdf5 = path + item.uuid + '_' + proc.UUID + '.hdf5'
                    proc.results.to_hdf5(result.hdf5)
                    result.save()

        del proc
        del pipe
        self.status_setter(3)
<commit_msg>Add sha1sum to item<commit_after># -*- coding: utf-8 -*-

import timeside, os, uuid, time, hashlib, mimetypes

from timeside.analyzer.core import AnalyzerResultContainer, AnalyzerResult
from timeside.decoder.utils import sha1sum_file

from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.contrib.auth.models import User

from jsonfield import JSONField

app = 'timeside'

processors = timeside.core.processors(timeside.api.IProcessor)

PROCESSOR_PIDS = [(processor.id(), processor.id())  for processor in processors]

PROCESSOR_TYPES = (('decoder', _('decoder')), ('analyzer', _('analyzer')),
                   ('grapher', _('grapher')), ('encoder', _('encoder')))

STATUS = ((0, _('failed')), (1, _('pending')), (2, _('running')),
                         (3, _('done')), (4, _('ready')))

def get_mime_type(path):
    return mimetypes.guess_type(path)[0]

def get_processor(pid):
    for proc in processors:
        if proc.id == pid:
            return proc()
    raise ValueError('Processor %s does not exists' % pid)

class MetaCore:

    app_label = app

class BaseResource(models.Model):

    date_added = models.DateTimeField(_('date added'), auto_now_add=True)
    date_modified = models.DateTimeField(_('date modified'), auto_now=True, null=True)
    uuid = models.CharField(_('uuid'), blank=True, max_length=512, )

    class Meta(MetaCore):
        abstract = True

    def save(self, **kwargs):
        if not self.uuid:
            self.uuid = uuid.uuid4()
        super(BaseResource, self).save(**kwargs)

class DocumentedBaseResource(BaseResource):

    title = models.CharField(_('title'), blank=True, max_length=512)
    description = models.TextField(_('description'), blank=True)

    def __unicode__(self):
        return self.title

    class Meta(MetaCore):
        abstract = True

class Collection(DocumentedBaseResource):

    items = models.ManyToManyField('Item', related_name="collections", verbose_name=_('items'), blank=True, null=True)

    class Meta(MetaCore):
        db_table = app + '_collections'
        ordering = ['title']
        verbose_name = _('collection')

class Item(DocumentedBaseResource):

    file = models.FileField(_('file'), upload_to='items/%Y/%m/%d', blank=True, max_length=1024)
    url = models.URLField(_('URL'), blank=True, max_length=1024)
    sha1 = models.CharField(_('sha1'), unique=True, blank=True, max_length=512)
    mime_type = models.CharField(_('mime type'), blank=True, max_length=256)
    hdf5 = models.FileField(_('HDF5 result file'), upload_to='items/%Y/%m/%d', blank=True, max_length=1024)
    lock = models.BooleanField(default=False)

    class Meta(MetaCore):
        db_table = app + '_items'
        ordering = ['title']
        verbose_name = _('item')

    def save(self, **kwargs):
        if self.file:
            if not self.mime_type:
                self.mime_type = get_mime_type(self.file.path)
            if not self.sha1:
                self.sha1 = sha1sum_file(self.file)
        super(Item, self).save(**kwargs)

    def results(self):
        return [result for result in self.results.all()]

class Experience(DocumentedBaseResource):

    processors = models.ManyToManyField('Processor', related_name="experiences", verbose_name=_('processors'), blank=True, null=True)
    author = models.ForeignKey(User, related_name="experiences", verbose_name=_('author'), blank=True, null=True, on_delete=models.SET_NULL)

    class Meta(MetaCore):
        db_table = app + '_experiences'
        verbose_name = _('Experience')

class Processor(BaseResource):

    pid = models.CharField(_('pid'), choices=PROCESSOR_PIDS, max_length=256)
    type = models.CharField(_('type'), choices=PROCESSOR_TYPES, default='none', max_length=64)
    parameters = JSONField(_('parameters'), blank=True, null=True)
    version = models.CharField(_('version'), max_length=64, blank=True)

    class Meta(MetaCore):
        db_table = app + '_processors'
        verbose_name = _('processor')

    def __unicode__(self):
        return '_'.join([self.type, self.pid, str(self.id)])

    def save(self, **kwargs):
        if not self.version:
            self.version = timeside.__version__
        super(Processor, self).save(**kwargs)

class Result(BaseResource):

    item = models.ForeignKey('Item', related_name="results", verbose_name=_('item'), blank=True, null=True, on_delete=models.SET_NULL)
    processor = models.ForeignKey('Processor', related_name="results", verbose_name=_('processor'), blank=True, null=True, on_delete=models.SET_NULL)
    json = JSONField(_('JSON result'), blank=True)
    hdf5 = models.FileField(_('HDF5 result file'), upload_to='results/%Y/%m/%d', blank=True, max_length=1024)
    output = models.FileField(_('Output file'), upload_to='results/%Y/%m/%d', blank=True, max_length=1024)
    output_mime_type = models.CharField(_('Output mime type'), blank=True, max_length=256)

    class Meta(MetaCore):
        db_table = app + '_results'
        verbose_name = _('Result')
        verbose_name_plural = _('Results')

    def __unicode__(self):
        return '_'.join([self.item.title, unicode(self.processor)])

    def save(self, **kwargs):
        if self.output:
            self.output_mime_type = get_mime_type(self.output.path)
        super(Result, self).save(**kwargs)

class Task(models.Model):

    experience = models.ForeignKey('Experience', related_name="task", verbose_name=_('experience'), blank=True, null=True)
    items = models.ManyToManyField('Item', related_name="task", verbose_name=_('items'), blank=True, null=True)
    status = models.IntegerField(_('status'), choices=STATUS, default=1)

    class Meta(MetaCore):
        db_table = app + '_tasks'
        verbose_name = _('Task')
        verbose_name_plural = _('Tasks')

    def __unicode__(self):
        return '_'.join([unicode(self.experience), unicode(self.id)])

    def status_setter(self, status):
        self.status = status
        self.save()

    def run(self):
        for item in self.items:
            pipe = timeside.decoder.FileDecoder(item.file)
            proc_dict = {}
            for processor in self.experience.processors.all():
                proc = get_processor(processor.id)
                #TODO: add parameters
                proc_dict[processor] = proc
                pipe = pipe | proc

            while item.lock:
                time.sleep(30)

            path = settings.MEDIA_ROOT + 'results' + os.sep + item.uuid + os.sep
            if not item.hdf5:
                item.hdf5 =  path + item.uuid + '.hdf5'
                item.save()

            try:
                self.status_setter(2)
                pipe.run()
                pipe.results.to_hdf5(item.hdf5)
            except:
                self.status_setter(0)

            if sef.status == 2:
                for processor in proc_dict.keys():
                    proc = proc_dict[processor]
                    results = Result.objects.filter(processor=processor, uuid=proc.UUID)
                    if not results:
                        result = Result(processor=processor, uuid=proc.UUID, item=item)
                    else:
                        result = results[0]
                    result.hdf5 = path + item.uuid + '_' + proc.UUID + '.hdf5'
                    proc.results.to_hdf5(result.hdf5)
                    result.save()

        del proc
        del pipe
        self.status_setter(3)
<|endoftext|>


<commit_before># empty for now
<commit_msg>allowed simplified import statements (from tincan import RemoteLRS) for external modules. Added package-level docstring.<commit_after>"""
Client library for communicating with an LRS (Learning Record Store)
implementing Tin Can API version 1.0.0 or 1.0.1.

Web site: <https://github.com/RusticiSoftware/TinCanPython>

For more info about the Tin Can API, see <http://tincanapi.com/>.
"""

# These imports are for convenience to external modules only.
# Internal tincan modules should continue to use explicit imports,
# since this file will not have run yet.
#
# For example, from the outside, you can say:
#    from tincan import RemoteLRS, LRSResponse
#
# but inside the tincan package, we have to use:
#    from tincan.remote_lrs import RemoteLRS
#    from tincan.lrs_response import LRSResponse

from about import About
from activity import Activity
from activity_definition import ActivityDefinition
from activity_list import ActivityList
from agent import Agent
from agent_account import AgentAccount
from agent_list import AgentList
from attachment import Attachment
from attachment_list import AttachmentList
from base import Base
from context import Context
from context_activities import ContextActivities
from extensions import Extensions
from group import Group
from http_request import HTTPRequest
from interaction_component import InteractionComponent
from interaction_component_list import InteractionComponentList
from language_map import LanguageMap
from lrs_response import LRSResponse
from remote_lrs import RemoteLRS
from result import Result
from score import Score
from serializable_base import SerializableBase
from statement import Statement
from statement_base import StatementBase
from statement_list import StatementList
from statement_ref import StatementRef
from statement_targetable import StatementTargetable
from statements_result import StatementsResult
from substatement import SubStatement
from typed_list import TypedList
from verb import Verb
from version import Version<|endoftext|>


<commit_before>"""
Contains the :class:`database <tinydb.database.TinyDB>` and
:class:`tables <tinydb.database.Table>` implementation.
"""
from typing import Dict, Iterator, Set

from tinydb.table import Table, Document
from . import JSONStorage
from .storages import Storage

class TinyDB:
    """
    The main class of TinyDB.

    Gives access to the database, provides methods to insert/search/remove
    and getting tables.
    """

    table_class = Table
    default_storage_class = JSONStorage

    def __init__(self, *args, **kwargs):
        """
        Create a new instance of TinyDB.

        All arguments and keyword arguments will be passed to the underlying
        storage class (default: :class:`~tinydb.storages.JSONStorage`).

        :param storage: The class of the storage to use. Will be initialized
                        with ``args`` and ``kwargs``.
        :param default_table: The name of the default table to populate.
        """

        storage = kwargs.pop('storage', self.default_storage_class)

        # Prepare the storage
        self._storage = storage(*args, **kwargs)  # type: Storage

        self._opened = True

        # Prepare the default table
        self._tables = {}  # type: Dict[str, Table]

    def __repr__(self):
        args = [
            'tables={}'.format(list(self.tables())),
            'tables_count={}'.format(len(self.tables())),
            'default_table_documents_count={}'.format(self.__len__()),
            'all_tables_documents_count={}'.format(
                ['{}={}'.format(table, len(self.table(table)))
                 for table in self.tables()]),
        ]

        return '<{} {}>'.format(type(self).__name__, ', '.join(args))

    def table(self, name: str = '_default', **options) -> Table:
        """
        Get access to a specific table.

        Creates a new table, if it hasn't been created before, otherwise it
        returns the cached :class:`~tinydb.Table` object.

        :param name: The name of the table.
        :param cache_size: How many query results to cache.
        """

        if name in self._tables:
            return self._tables[name]

        self._tables[name] = self.table_class(self.storage, name, **options)

        return self._tables[name]

    def tables(self) -> Set[str]:
        """
        Get the names of all tables in the database.

        :returns: a set of table names
        """

        return set(self.storage.read() or {})

    def drop_tables(self) -> None:
        """
        Drop all tables from the database. **CANNOT BE REVERSED!**
        """

        self.storage.write({})
        self._tables.clear()

    def drop_table(self, name: str) -> None:
        """
        Drop a specific table from the database. **CANNOT BE REVERSED!**

        :param name: The name of the table.
        """
        if name in self._tables:
            del self._tables[name]

        data = self.storage.read()

        if data is None:
            return

        if name not in data:
            return

        del data[name]
        self.storage.write(data)

    @property
    def storage(self) -> Storage:
        """
        Access the storage used for this TinyDB instance.

        :return: This instance's storage
        """
        return self._storage

    def close(self) -> None:
        """
        Close the database.
        """
        self._opened = False
        self.storage.close()

    def __enter__(self):
        return self

    def __exit__(self, *args):
        if self._opened:
            self.close()

    def __getattr__(self, name):
        """
        Forward all unknown attribute calls to the underlying default table.
        """
        return getattr(self.table(), name)

    # Methods that are executed on the default table
    # Because magic methods are not handled by __getattr__ we need to forward
    # them manually here

    def __len__(self):
        """
        Get the total number of documents in the default table.

        >>> db = TinyDB('db.json')
        >>> len(db)
        0
        """
        return len(self.table())

    def __iter__(self) -> Iterator[Document]:
        """
        Iter over all documents from default table.
        """
        return iter(self.table())
<commit_msg>docs(database): improve code documentation<commit_after>"""
This module contains the main component of TinyDB: the database.
"""
from typing import Dict, Iterator, Set

from . import JSONStorage
from .storages import Storage
from .table import Table, Document

class TinyDB:
    """
    The main class of TinyDB.

    The ``TinyDB`` class is responsible for creating the storage class instance
    that will store this database's documents, managing the database
    tables as well as providing access to the default table.

    For table management, a simple ``dict`` is used that stores the table class
    instances accessible using their table name.

    Default table access is provided by forwarding all unknown method calls
    and property access operations to the default table by implementing
    ``__getattr__``.

    When creating a new instance, all arguments and keyword arguments (except
    for ``storage``) will be passed to the storage class that is provided. If
    no storage class is specified, :class:`~tinydb.storages.JSONStorage` wil be
    used.

    .. admonition:: Customization

        For customization, the following class variables can be set:

        - ``table_class`` defines the class that is used to create tables,
        - ``default_table_name`` defines the name of the default table, and
        - ``default_storage_class`` will define the class that will be used to
          create storage instances if no other storage is passed.

        .. versionadded:: 4.0

    .. admonition:: Data Storage Model

        Data is stored using a storage class that provides persistence for a
        ``dict`` instance. This ``dict`` contains all tables and their data.
        The data is modelled like this::

            {
                'table1': {
                    0: {document...},
                    1: {document...},
                },
                'table2': {
                    ...
                }
            }

        Each entry in this ``dict`` uses the table name as its key and a
        ``dict`` of documents as its value. The document ``dict`` contains
        document IDs as keys and the documents themselves as values.

    :param storage: The class of the storage to use. Will be initialized
                    with ``args`` and ``kwargs``.
    """

    #: The class that will be used to create table instances
    #:
    #: .. versionadded:: 4.0
    table_class = Table

    #: The class that will be used by default to create storage instances
    #:
    #: .. versionadded:: 4.0
    default_storage_class = JSONStorage

    def __init__(self, *args, **kwargs):
        """
        Create a new instance of TinyDB.
        """

        storage = kwargs.pop('storage', self.default_storage_class)

        # Prepare the storage
        self._storage = storage(*args, **kwargs)  # type: Storage

        self._opened = True
        self._tables = {}  # type: Dict[str, Table]

    def __repr__(self):
        args = [
            'tables={}'.format(list(self.tables())),
            'tables_count={}'.format(len(self.tables())),
            'default_table_documents_count={}'.format(self.__len__()),
            'all_tables_documents_count={}'.format(
                ['{}={}'.format(table, len(self.table(table)))
                 for table in self.tables()]),
        ]

        return '<{} {}>'.format(type(self).__name__, ', '.join(args))

    def table(self, name: str = '_default', **options) -> Table:
        """
        Get access to a specific table.

        If the table hasn't been accessed yet, a new table instance will be
        created using the :attr:`~tinydb.database.TinyDB.table_class` class.
        Otherwise, the previously created table instance wil be returned.

        All futher options besides the name are passed to the table class which
        by default is :class:`~tinydb.table.Table`. Check its documentation
        for further parameters you can pass.

        :param name: The name of the table.
        :param options: Keyword arguments to pass to the table class constructor
        """

        if name in self._tables:
            return self._tables[name]

        table = self.table_class(self.storage, name, **options)
        self._tables[name] = table

        return table

    def tables(self) -> Set[str]:
        """
        Get the names of all tables in the database.

        :returns: a set of table names
        """

        # TinyDB stores data as a dict of tables like this:
        #
        #   {
        #       '_default': {
        #           0: {document...},
        #           1: {document...},
        #       },
        #       'table1': {
        #           ...
        #       }
        #   }
        #
        # To get a set of table names, we thus construct a set of this main
        # dict which returns a set of the dict keys which are the table names.
        #
        # Storage.read() may return ``None`` if the database file is empty
        # so we need to consider this case to and return an empty set in this
        # case.

        return set(self.storage.read() or {})

    def drop_tables(self) -> None:
        """
        Drop all tables from the database. **CANNOT BE REVERSED!**
        """

        # We drop all tables from this database by writing an empty dict
        # to the storage thereby returning to the initial state with no tables.
        self.storage.write({})

        # After that we need to remeber to empty the ``_tables`` dict so we'll
        # create new table instances when a table is accessed again.
        self._tables.clear()

    def drop_table(self, name: str) -> None:
        """
        Drop a specific table from the database. **CANNOT BE REVERSED!**

        :param name: The name of the table to drop.
        """

        # If the table is currently opened, we need to forget the table class
        # instance
        if name in self._tables:
            del self._tables[name]

        data = self.storage.read()

        # The database is uninitialized, there's nothing to do
        if data is None:
            return

        # The table does not exist, there's nothing to do
        if name not in data:
            return

        # Remove the table from the data dict
        del data[name]

        # Store the updated data back to the storage
        self.storage.write(data)

    @property
    def storage(self) -> Storage:
        """
        Get the storage instance used for this TinyDB instance.

        :return: This instance's storage
        :rtype: Storage
        """
        return self._storage

    def close(self) -> None:
        """
        Close the database.

        This may be needed if the storage instance used for this database
        needs to perform cleanup operations like closing file handles.

        To ensure this method is called, the TinyDB instance can be used as a
        context manager::

            with TinyDB('data.json') as db:
                db.insert({'foo': 'bar'})

        Upon leaving this context, the ``close`` method will be called.
        """
        self._opened = False
        self.storage.close()

    def __enter__(self):
        """
        Use the database as a context manager.

        Using the database as a context manager ensures that the
        :meth:`~tinydb.database.TinyDB.close` method is called upon leaving
        the context.

        :return: The current instance
        """
        return self

    def __exit__(self, *args):
        """
        Close the storage instance when leaving a context.
        """
        if self._opened:
            self.close()

    def __getattr__(self, name):
        """
        Forward all unknown attribute calls to the default table instance.
        """
        return getattr(self.table(), name)

    # Here we forward magic methods to the default table instance. These are
    # not handled by __getattr__ so we need to forward them manually here

    def __len__(self):
        """
        Get the total number of documents in the default table.

        >>> db = TinyDB('db.json')
        >>> len(db)
        0
        """
        return len(self.table())

    def __iter__(self) -> Iterator[Document]:
        """
        Return an iterater for the default table's documents.
        """
        return iter(self.table())
<|endoftext|>


<commit_before># Copyright (c) 2008 Joost Cassee
# Licensed under the terms of the MIT License (see LICENSE.txt)

"""
This TinyMCE widget was copied and extended from this code by John D'Agostino:
http://code.djangoproject.com/wiki/CustomWidgetsTinyMCE
"""
from __future__ import unicode_literals

from collections import OrderedDict
import json

from django import forms
from django.conf import settings
from django.contrib.admin import widgets as admin_widgets
from django.core.urlresolvers import reverse
from django.forms.widgets import flatatt
from django.utils.encoding import force_text
from django.utils.html import escape
from django.utils.safestring import mark_safe
from django.utils.translation import get_language, ugettext as _

import tinymce.settings

class TinyMCE(forms.Textarea):
    """
    TinyMCE widget. Set settings.TINYMCE_JS_URL to set the location of the
    javascript file. Default is "MEDIA_URL + 'js/tiny_mce/tiny_mce.js'".
    You can customize the configuration with the mce_attrs argument to the
    constructor.

    In addition to the standard configuration you can set the
    'content_language' parameter. It takes the value of the 'language'
    parameter by default.

    In addition to the default settings from settings.TINYMCE_DEFAULT_CONFIG,
    this widget sets the 'language', 'directionality' and
    'spellchecker_languages' parameters by default. The first is derived from
    the current Django language, the others from the 'content_language'
    parameter.
    """
    def __init__(self, content_language=None, attrs=None, mce_attrs=None):
        super(TinyMCE, self).__init__(attrs)
        mce_attrs = mce_attrs or {}
        self.mce_attrs = mce_attrs
        if 'mode' not in self.mce_attrs:
            self.mce_attrs['mode'] = 'exact'
        self.mce_attrs['strict_loading_mode'] = 1
        if content_language is None:
            content_language = mce_attrs.get('language', None)
        self.content_language = content_language

    def get_mce_config(self, attrs):
        mce_config = tinymce.settings.DEFAULT_CONFIG.copy()
        mce_config.update(get_language_config(self.content_language))
        if tinymce.settings.USE_FILEBROWSER:
            mce_config['file_browser_callback'] = "djangoFileBrowser"
        mce_config.update(self.mce_attrs)
        if mce_config['mode'] == 'exact':
            mce_config['elements'] = attrs['id']
        return mce_config

    def get_mce_json(self, mce_config):
        # Fix for js functions
        js_functions = {}
        for k in ('paste_preprocess', 'paste_postprocess'):
            if k in mce_config:
                js_functions[k] = mce_config[k]
                del mce_config[k]
        mce_json = json.dumps(mce_config)
        for k in js_functions:
            index = mce_json.rfind('}')
            mce_json = mce_json[:index] + ', ' + k + ':' + js_functions[k].strip() + mce_json[index:]
        return mce_json

    def render(self, name, value, attrs=None):
        if value is None:
            value = ''
        value = force_text(value)
        final_attrs = self.build_attrs(attrs)
        final_attrs['name'] = name
        if final_attrs.get('class', None) is None:
            final_attrs['class'] = 'tinymce'
        else:
            final_attrs['class'] = ' '.join(final_attrs['class'].split(' ') + ['tinymce'])
        assert 'id' in final_attrs, "TinyMCE widget attributes must contain 'id'"
        mce_config = self.get_mce_config(final_attrs)
        mce_json = self.get_mce_json(mce_config)
        if tinymce.settings.USE_COMPRESSOR:
            compressor_config = {
                'plugins': mce_config.get('plugins', ''),
                'themes': mce_config.get('theme', 'advanced'),
                'languages': mce_config.get('language', ''),
                'diskcache': True,
                'debug': False,
            }
            final_attrs['data-mce-gz-conf'] = json.dumps(compressor_config)
        final_attrs['data-mce-conf'] = mce_json
        html = ['<textarea{!s}>{!s}</textarea>'.format(flatatt(final_attrs), escape(value))]
        return mark_safe('\n'.join(html))

    def _media(self):
        if tinymce.settings.USE_COMPRESSOR:
            js = [reverse('tinymce-compressor')]
        else:
            js = [tinymce.settings.JS_URL]
        if tinymce.settings.USE_FILEBROWSER:
            js.append(reverse('tinymce-filebrowser'))
        js.append('django_tinymce/jquery-1.9.1.min.js')
        js.append('django_tinymce/init_tinymce.js')
        return forms.Media(js=js)
    media = property(_media)

class AdminTinyMCE(TinyMCE, admin_widgets.AdminTextareaWidget):
    pass

def get_language_config(content_language=None):
    language = get_language()[:2]
    if content_language:
        content_language = content_language[:2]
    else:
        content_language = language

    config = {}
    config['language'] = language

    lang_names = OrderedDict()
    for lang, name in settings.LANGUAGES:
        if lang[:2] not in lang_names:
            lang_names[lang[:2]] = []
        lang_names[lang[:2]].append(_(name))
    sp_langs = []
    for lang, names in lang_names.items():
        if lang == content_language:
            default = '+'
        else:
            default = ''
        sp_langs.append('{!s}{!s}={!s}'.format(default, ' / '.join(names), lang))

    config['spellchecker_languages'] = ','.join(sp_langs)

    if content_language in settings.LANGUAGES_BIDI:
        config['directionality'] = 'rtl'
    else:
        config['directionality'] = 'ltr'

    if tinymce.settings.USE_SPELLCHECKER:
        config['spellchecker_rpc_url'] = reverse('tinymce-spellcheck')

    return config
<commit_msg>Fixed paste_preprocess & paste_postprocess if set in TINYMCE_DEFAULT_CONFIG<commit_after># Copyright (c) 2008 Joost Cassee
# Licensed under the terms of the MIT License (see LICENSE.txt)

"""
This TinyMCE widget was copied and extended from this code by John D'Agostino:
http://code.djangoproject.com/wiki/CustomWidgetsTinyMCE
"""
from __future__ import unicode_literals

from collections import OrderedDict
import json

from django import forms
from django.conf import settings
from django.contrib.admin import widgets as admin_widgets
from django.core.urlresolvers import reverse
from django.forms.widgets import flatatt
from django.utils.encoding import force_text
from django.utils.html import escape
from django.utils.safestring import mark_safe
from django.utils.translation import get_language, ugettext as _

import tinymce.settings

class TinyMCE(forms.Textarea):
    """
    TinyMCE widget. Set settings.TINYMCE_JS_URL to set the location of the
    javascript file. Default is "MEDIA_URL + 'js/tiny_mce/tiny_mce.js'".
    You can customize the configuration with the mce_attrs argument to the
    constructor.

    In addition to the standard configuration you can set the
    'content_language' parameter. It takes the value of the 'language'
    parameter by default.

    In addition to the default settings from settings.TINYMCE_DEFAULT_CONFIG,
    this widget sets the 'language', 'directionality' and
    'spellchecker_languages' parameters by default. The first is derived from
    the current Django language, the others from the 'content_language'
    parameter.
    """
    def __init__(self, content_language=None, attrs=None, mce_attrs=None):
        super(TinyMCE, self).__init__(attrs)
        mce_attrs = mce_attrs or {}
        self.mce_attrs = mce_attrs
        if 'mode' not in self.mce_attrs:
            self.mce_attrs['mode'] = 'exact'
        self.mce_attrs['strict_loading_mode'] = 1
        if content_language is None:
            content_language = mce_attrs.get('language', None)
        self.content_language = content_language

    def get_mce_config(self, attrs):
        mce_config = tinymce.settings.DEFAULT_CONFIG.copy()
        mce_config.update(get_language_config(self.content_language))
        if tinymce.settings.USE_FILEBROWSER:
            mce_config['file_browser_callback'] = "djangoFileBrowser"
        mce_config.update(self.mce_attrs)
        if mce_config['mode'] == 'exact':
            mce_config['elements'] = attrs['id']
        return mce_config

    def get_mce_json(self, mce_config):
        # Fix for js functions
        js_functions = {}
        for k in ('paste_preprocess', 'paste_postprocess'):
            if k in mce_config:
                js_functions[k] = mce_config[k]
                del mce_config[k]
        mce_json = json.dumps(mce_config)
        for k in js_functions:
            index = mce_json.rfind('}')
            mce_json = mce_json[:index] + ', \"' + k + '\":\"' + js_functions[k].strip() + '\"' + mce_json[index:]
        return mce_json

    def render(self, name, value, attrs=None):
        if value is None:
            value = ''
        value = force_text(value)
        final_attrs = self.build_attrs(attrs)
        final_attrs['name'] = name
        if final_attrs.get('class', None) is None:
            final_attrs['class'] = 'tinymce'
        else:
            final_attrs['class'] = ' '.join(final_attrs['class'].split(' ') + ['tinymce'])
        assert 'id' in final_attrs, "TinyMCE widget attributes must contain 'id'"
        mce_config = self.get_mce_config(final_attrs)
        mce_json = self.get_mce_json(mce_config)
        if tinymce.settings.USE_COMPRESSOR:
            compressor_config = {
                'plugins': mce_config.get('plugins', ''),
                'themes': mce_config.get('theme', 'advanced'),
                'languages': mce_config.get('language', ''),
                'diskcache': True,
                'debug': False,
            }
            final_attrs['data-mce-gz-conf'] = json.dumps(compressor_config)
        final_attrs['data-mce-conf'] = mce_json
        html = ['<textarea{!s}>{!s}</textarea>'.format(flatatt(final_attrs), escape(value))]
        return mark_safe('\n'.join(html))

    def _media(self):
        if tinymce.settings.USE_COMPRESSOR:
            js = [reverse('tinymce-compressor')]
        else:
            js = [tinymce.settings.JS_URL]
        if tinymce.settings.USE_FILEBROWSER:
            js.append(reverse('tinymce-filebrowser'))
        js.append('django_tinymce/jquery-1.9.1.min.js')
        js.append('django_tinymce/init_tinymce.js')
        return forms.Media(js=js)
    media = property(_media)

class AdminTinyMCE(TinyMCE, admin_widgets.AdminTextareaWidget):
    pass

def get_language_config(content_language=None):
    language = get_language()[:2]
    if content_language:
        content_language = content_language[:2]
    else:
        content_language = language

    config = {}
    config['language'] = language

    lang_names = OrderedDict()
    for lang, name in settings.LANGUAGES:
        if lang[:2] not in lang_names:
            lang_names[lang[:2]] = []
        lang_names[lang[:2]].append(_(name))
    sp_langs = []
    for lang, names in lang_names.items():
        if lang == content_language:
            default = '+'
        else:
            default = ''
        sp_langs.append('{!s}{!s}={!s}'.format(default, ' / '.join(names), lang))

    config['spellchecker_languages'] = ','.join(sp_langs)

    if content_language in settings.LANGUAGES_BIDI:
        config['directionality'] = 'rtl'
    else:
        config['directionality'] = 'ltr'

    if tinymce.settings.USE_SPELLCHECKER:
        config['spellchecker_rpc_url'] = reverse('tinymce-spellcheck')

    return config
<|endoftext|>


<commit_before>import os
import shutil
import sys
import subprocess
import time

travis = False
if "TRAVIS" in os.environ and os.environ["TRAVIS"] == "true":
    travis = True

success_count = 0
fail_count = 0
exit_status = 0

all_examples = [];
for entry in os.scandir("examples/device"):
    if entry.is_dir():
        all_examples.append(entry.name)

# mynewt has its own example repo
all_examples.remove("cdc_msc_hid_mynewt")

# TODO update freeRTOS example to work with all boards (only nrf52840 now)
all_examples.remove("cdc_msc_hid_freertos")

all_boards = []
for entry in os.scandir("hw/bsp"):
    if entry.is_dir():
        all_boards.append(entry.name)

def build_example(example, board):
    subprocess.run("make -C examples/device/{} BOARD={} clean".format(example, board), shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    return subprocess.run("make -j 4 -C examples/device/{} BOARD={} all".format(example, board), shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

total_time = time.monotonic()

for example in all_examples:
    for board in all_boards:
        start_time = time.monotonic()
        build_result = build_example(example, board)
        build_duration = time.monotonic() - start_time

        if build_result.returncode != 0:
            exit_status = build_result.returncode
            success = "\033[31mfailed\033[0m"
            fail_count += 1
        else:
            success = "\033[32msucceeded\033[0m"
            success_count += 1

        if travis:
            print('travis_fold:start:build-{}-{}\\r'.format(example, board))
        print("Build {} on {} took {:.2f}s and {}".format(example, board, build_duration, success))
        if build_result.returncode != 0:
            print(build_result.stdout.decode("utf-8"))
        if travis:
            print('travis_fold:end:build-{}-{}\\r'.format(example, board))

# FreeRTOS example
#example = 'cdc_msc_hid_freertos'
#board = 'pca10056'
#build_example(example, board)

total_time = time.monotonic() - total_time

print("Build Sumamary: {} \033[32msucceeded\033[0m, {} \033[31mfailed\033[0m".format(success_count, fail_count))
print("Total build time took {:.2f}s".format(total_time))

sys.exit(exit_status)
<commit_msg>format travis build<commit_after>import os
import shutil
import sys
import subprocess
import time

travis = False
if "TRAVIS" in os.environ and os.environ["TRAVIS"] == "true":
    travis = True

success_count = 0
fail_count = 0
exit_status = 0

total_time = time.monotonic()

all_examples = []
for entry in os.scandir("examples/device"):
    if entry.is_dir():
        all_examples.append(entry.name)

# mynewt has its own example repo
all_examples.remove("cdc_msc_hid_mynewt")

# TODO update freeRTOS example to work with all boards (only nrf52840 now)
all_examples.remove("cdc_msc_hid_freertos")

all_boards = []
for entry in os.scandir("hw/bsp"):
    if entry.is_dir():
        all_boards.append(entry.name)

def build_example(example, board):
    subprocess.run("make -C examples/device/{} BOARD={} clean".format(example, board), shell=True,
                   stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    return subprocess.run("make -j 4 -C examples/device/{} BOARD={} all".format(example, board), shell=True,
                          stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

build_format = '| {:30} | {:30} | {:9} '
build_separator = '-' * 87
print(build_separator)
print((build_format + '| {:5} |').format('Example', 'Board', 'Result', 'Time'))
for example in all_examples:
    print(build_separator)
    for board in all_boards:
        start_time = time.monotonic()
        build_result = build_example(example, board)
        build_duration = time.monotonic() - start_time

        if build_result.returncode != 0:
            exit_status = build_result.returncode
            success = "\033[31mfailed\033[0m"
            fail_count += 1
        else:
            success = "\033[32msucceeded\033[0m"
            success_count += 1

        if travis:
            print('travis_fold:start:build-{}-{}\\r'.format(example, board))

        print((build_format + '| {:.2f}s |').format(example, board, success, build_duration))
        if build_result.returncode != 0:
            print(build_result.stdout.decode("utf-8"))

        if travis:
            print('travis_fold:end:build-{}-{}\\r'.format(example, board))

# FreeRTOS example
# example = 'cdc_msc_hid_freertos'
# board = 'pca10056'
# build_example(example, board)

total_time = time.monotonic() - total_time
print(build_separator)
print("Build Sumamary: {} \033[32msucceeded\033[0m, {} \033[31mfailed\033[0m and took {:.2f}s".format(success_count, fail_count, total_time))
print(build_separator)

sys.exit(exit_status)
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-

import os
import sys
from pprint import pprint

root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
sys.path.append(root + '/python')

import ccxt  # noqa: E402

print('CCXT Version:', ccxt.__version__)

exchange = ccxt.phemex({
    'enableRateLimit': True,  # https://github.com/ccxt/ccxt/wiki/Manual#rate-limit
    'apiKey': 'YOUR_API_KEY',  # testnet keys if using the testnet sandbox
    'secret': 'YOUR_SECRET',  # testnet keys if using the testnet sandbox
    'options': {
        'defaultType': 'swap',
    },
})

# exchange.set_sandbox_mode(True)  # uncomment to use the testnet sandbox

markets = exchange.load_markets()

amount = 20
symbol = 'BTC/USD:USD'

# Opening and Canceling a pending contract (limit) order
order = exchange.create_order(symbol, 'limit', 'buy', amount, '20000')
response = exchange.cancel_order(order['id'], symbol)
pprint(response)

# Opening and Canceling a pending contract (stop-market) order
stopMarketOrder = exchange.create_order(symbol, 'Stop', 'buy', amount, None, {'stopPx': 70000, "triggerType": "ByLastPrice"})
stopMarketResponse = exchange.cancel_order(stopMarketOrder['id'], symbol)
pprint(stopMarketResponse)

# Opening and Canceling a pending contract (stop-limit) order
stopLimitOrder = exchange.create_order(symbol, 'StopLimit', 'buy', amount, 20000, {'stopPx': 70000, "triggerType": "ByLastPrice"})
stopLimitResponse = exchange.cancel_order(stopLimitOrder['id'], symbol)
pprint(stopLimitResponse)

# Opening and exiting a filled contract position by issuing the exact same order but in the opposite direction
order = exchange.create_order(symbol, 'market', 'buy', amount)
# closing the previous position by issuing the exact same order but in the opposite direction
# with reduceOnly option to prevent an unwanted exposure increase
orderClose = exchange.create_order(symbol, 'market', 'sell', amount, None, {'reduceOnly': True})

# Opening a contract position (market order) with TakeProfit and StopLoss prices defined
order = exchange.create_order(symbol, 'market', 'buy', amount, None, {'stopLossPrice': 5000, 'takeProfitPrice': 100000})

# Opening a contract trailing (stop-limit) order
ethSymbol = 'ETH/USD:USD'
ethPrice = 1000
stopPrice = 5000
trailingOrder = exchange.create_order(symbol = ethSymbol, type = 'StopLimit', side = 'buy', amount = 1, price = ethPrice, params = {
    'stopPrice': stopPrice,
    'ordType': 'StopLimit',
    'pegPriceType': 'TrailingStopPeg',
    'pegOffsetValueEp': 10000, # needs to be scaled
    'triggerType': 'ByMarkPrice'
    }
)
pprint(trailingOrder)
<commit_msg>adjust example<commit_after># -*- coding: utf-8 -*-

import os
import sys
from pprint import pprint

root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
sys.path.append(root + '/python')

import ccxt  # noqa: E402

print('CCXT Version:', ccxt.__version__)

exchange = ccxt.phemex({
    'enableRateLimit': True,
	'apiKey': 'YOUR_API_KEY',
	'secret': 'YOUR_SECRET',
	'options': {
	'defaultType': 'swap',
	},
})

# exchange.set_sandbox_mode(True)  # uncomment to use the testnet sandbox

markets = exchange.load_markets()

amount = 20
symbol = 'BTC/USD:USD'

# Opening and Canceling a pending contract (limit) order
order = exchange.create_order(symbol, 'limit', 'buy', amount, '20000')
response = exchange.cancel_order(order['id'], symbol)
pprint(response)

# Opening and Canceling a pending contract (stop-market) order
stopMarketOrder = exchange.create_order(symbol, 'Stop', 'buy', amount, None, {'stopPx': 70000}) # default triggerType is ByMarkPrice
stopMarketResponse = exchange.cancel_order(stopMarketOrder['id'], symbol)
pprint(stopMarketResponse)

# Opening and Canceling a pending contract (stop-limit) order
stopLimitOrder = exchange.create_order(symbol, 'StopLimit', 'buy', amount, 20000, {'stopPx': 70000, "triggerType": "ByLastPrice"})
stopLimitResponse = exchange.cancel_order(stopLimitOrder['id'], symbol)
pprint(stopLimitResponse)

# Opening and exiting a filled contract position by issuing the exact same order but in the opposite direction
order = exchange.create_order(symbol, 'market', 'buy', amount)
# closing the previous position by issuing the exact same order but in the opposite direction
# with reduceOnly option to prevent an unwanted exposure increase
orderClose = exchange.create_order(symbol, 'market', 'sell', amount, None, {'reduceOnly': True})

# Opening a contract position (market order) with TakeProfit and StopLoss prices defined
order = exchange.create_order(symbol, 'market', 'buy', amount, None, {'stopLossPrice': 5000, 'takeProfitPrice': 100000})

# Opening a contract trailing (stop-limit) order
ethSymbol = 'ETH/USD:USD'
ethPrice = 1000
stopPrice = 5000
trailingOrder = exchange.create_order(symbol = ethSymbol, type = 'StopLimit', side = 'buy', amount = 1, price = ethPrice, params = {
    'stopPrice': stopPrice,
    'ordType': 'StopLimit',
    'pegPriceType': 'TrailingStopPeg',
    'pegOffsetValueEp': 10000, # needs to be scaled
    } # default triggerType is ByMarkPrice
)
pprint(trailingOrder)<|endoftext|>