<commit_before>"""
Handles freezing of models into FakeORMs.
"""

import sys

from django.db import models
from django.contrib.contenttypes.generic import GenericRelation

from south.orm import FakeORM
from south import modelsinspector

def freeze_apps(apps):
    """
    Takes a list of app labels, and returns a string of their frozen form.
    """
    if isinstance(apps, basestring):
        apps = [apps]
    frozen_models = set()
    # For each app, add in all its models
    for app in apps:
        for model in models.get_models(models.get_app(app)):
            # Only add if it's not abstract or proxy
            if not model._meta.abstract and not getattr(model._meta, "proxy", False):
                frozen_models.add(model)
    # Now, add all the dependencies
    for model in list(frozen_models):
        frozen_models.update(model_dependencies(model))
    # Serialise!
    model_defs = {}
    for model in frozen_models:
        model_defs[model_key(model)] = prep_for_freeze(model)
    # Check for any custom fields that failed to freeze.
    missing_fields = False
    for key, fields in model_defs.items():
        for field_name, value in fields.items():
            if value is None:
                missing_fields = True
                print " ! Cannot freeze field '%s.%s'" % (key, field_name)
    if missing_fields:
        print ""
        print " ! South cannot introspect some fields; this is probably because they are custom"
        print " ! fields. If they worked in 0.6 or below, this is because we have removed the"
        print " ! models parser (it often broke things)."
        print " ! To fix this, read http://south.aeracode.org/wiki/MyFieldsDontWork"
        sys.exit(1)

    return model_defs

def freeze_apps_to_string(apps):
    return pprint_frozen_models(freeze_apps(apps))

###

def model_key(model):
    "For a given model, return 'appname.modelname'."
    return "%s.%s" % (model._meta.app_label, model._meta.object_name.lower())

def prep_for_freeze(model):
    """
    Takes a model and returns the ready-to-serialise dict (all you need
    to do is just pretty-print it).
    """
    fields = modelsinspector.get_model_fields(model, m2m=True)
    # Remove useless attributes (like 'choices')
    for name, field in fields.items():
        fields[name] = remove_useless_attributes(field)
    # See if there's a Meta
    fields['Meta'] = remove_useless_meta(modelsinspector.get_model_meta(model))
    # Add in our own special items to track the object name and managed
    fields['Meta']['object_name'] = model._meta.object_name # Special: not eval'able.
    if not getattr(model._meta, "managed", True):
        fields['Meta']['managed'] = repr(model._meta.managed)
    return fields

### Dependency resolvers

def model_dependencies(model, checked_models=None):
    """
    Returns a set of models this one depends on to be defined; things like
    OneToOneFields as ID, ForeignKeys everywhere, etc.
    """
    depends = set()
    checked_models = checked_models or set()
    # Get deps for each field
    for field in model._meta.fields + model._meta.many_to_many:
        depends.update(field_dependencies(field))
    # Add in any non-abstract bases
    for base in model.__bases__:
        if isinstance(base, models.Model) and not base._meta.abstract:
            depends.add(base)
    # Now recurse
    new_to_check = depends - checked_models
    while new_to_check:
        checked_model = new_to_check.pop()
        if checked_model == model or checked_model in checked_models:
            continue
        checked_models.add(checked_model)
        deps = model_dependencies(checked_model, checked_models)
        # Loop through dependencies...
        for dep in deps:
            # If the new dep is not already checked, add to the queue
            if (dep not in depends) and (dep not in new_to_check) and (dep not in checked_models):
                new_to_check.add(dep)
            depends.add(dep)
    return depends

def field_dependencies(field, checked_models=None):
    checked_models = checked_models or set()
    depends = set()
    if isinstance(field, (models.OneToOneField, models.ForeignKey, models.ManyToManyField, GenericRelation)):
        if field.rel.to in checked_models:
            return depends
        checked_models.add(field.rel.to)
        depends.add(field.rel.to)
        depends.update(field_dependencies(field.rel.to._meta.pk, checked_models))
    return depends

### Prettyprinters

def pprint_frozen_models(models):
    return "{\n        %s\n    }" % ",\n        ".join([
        "%r: %s" % (name, pprint_fields(fields))
        for name, fields in sorted(models.items())
    ])

def pprint_fields(fields):
    return "{\n            %s\n        }" % ",\n            ".join([
        "%r: %r" % (name, defn)
        for name, defn in sorted(fields.items())
    ])

### Output sanitisers

USELESS_KEYWORDS = ["choices", "help_text", "upload_to", "verbose_name", "storage"]
USELESS_DB_KEYWORDS = ["related_name", "default"] # Important for ORM, not for DB.

def remove_useless_attributes(field, db=False):
    "Removes useless (for database) attributes from the field's defn."
    # Work out what to remove, and remove it.
    keywords = USELESS_KEYWORDS[:]
    if db:
        keywords += USELESS_DB_KEYWORDS[:]
    if field:
        for name in keywords:
            if name in field[2]:
                del field[2][name]
    return field

USELESS_META = ["verbose_name", "verbose_name_plural"]
def remove_useless_meta(meta):
    "Removes useless (for database) attributes from the table's meta."
    if meta:
        for name in USELESS_META:
            if name in meta:
                del meta[name]
    return meta<commit_msg>Follow through= in M2Ms for dependencies<commit_after>"""
Handles freezing of models into FakeORMs.
"""

import sys

from django.db import models
from django.contrib.contenttypes.generic import GenericRelation

from south.orm import FakeORM
from south import modelsinspector

def freeze_apps(apps):
    """
    Takes a list of app labels, and returns a string of their frozen form.
    """
    if isinstance(apps, basestring):
        apps = [apps]
    frozen_models = set()
    # For each app, add in all its models
    for app in apps:
        for model in models.get_models(models.get_app(app)):
            # Only add if it's not abstract or proxy
            if not model._meta.abstract and not getattr(model._meta, "proxy", False):
                frozen_models.add(model)
    # Now, add all the dependencies
    for model in list(frozen_models):
        frozen_models.update(model_dependencies(model))
    # Serialise!
    model_defs = {}
    for model in frozen_models:
        model_defs[model_key(model)] = prep_for_freeze(model)
    # Check for any custom fields that failed to freeze.
    missing_fields = False
    for key, fields in model_defs.items():
        for field_name, value in fields.items():
            if value is None:
                missing_fields = True
                print " ! Cannot freeze field '%s.%s'" % (key, field_name)
    if missing_fields:
        print ""
        print " ! South cannot introspect some fields; this is probably because they are custom"
        print " ! fields. If they worked in 0.6 or below, this is because we have removed the"
        print " ! models parser (it often broke things)."
        print " ! To fix this, read http://south.aeracode.org/wiki/MyFieldsDontWork"
        sys.exit(1)

    return model_defs

def freeze_apps_to_string(apps):
    return pprint_frozen_models(freeze_apps(apps))

###

def model_key(model):
    "For a given model, return 'appname.modelname'."
    return "%s.%s" % (model._meta.app_label, model._meta.object_name.lower())

def prep_for_freeze(model):
    """
    Takes a model and returns the ready-to-serialise dict (all you need
    to do is just pretty-print it).
    """
    fields = modelsinspector.get_model_fields(model, m2m=True)
    # Remove useless attributes (like 'choices')
    for name, field in fields.items():
        fields[name] = remove_useless_attributes(field)
    # See if there's a Meta
    fields['Meta'] = remove_useless_meta(modelsinspector.get_model_meta(model))
    # Add in our own special items to track the object name and managed
    fields['Meta']['object_name'] = model._meta.object_name # Special: not eval'able.
    if not getattr(model._meta, "managed", True):
        fields['Meta']['managed'] = repr(model._meta.managed)
    return fields

### Dependency resolvers

def model_dependencies(model, checked_models=None):
    """
    Returns a set of models this one depends on to be defined; things like
    OneToOneFields as ID, ForeignKeys everywhere, etc.
    """
    depends = set()
    checked_models = checked_models or set()
    # Get deps for each field
    for field in model._meta.fields + model._meta.many_to_many:
        depends.update(field_dependencies(field))
    # Add in any non-abstract bases
    for base in model.__bases__:
        if isinstance(base, models.Model) and not base._meta.abstract:
            depends.add(base)
    # Now recurse
    new_to_check = depends - checked_models
    while new_to_check:
        checked_model = new_to_check.pop()
        if checked_model == model or checked_model in checked_models:
            continue
        checked_models.add(checked_model)
        deps = model_dependencies(checked_model, checked_models)
        # Loop through dependencies...
        for dep in deps:
            # If the new dep is not already checked, add to the queue
            if (dep not in depends) and (dep not in new_to_check) and (dep not in checked_models):
                new_to_check.add(dep)
            depends.add(dep)
    return depends

def field_dependencies(field, checked_models=None):
    checked_models = checked_models or set()
    depends = set()
    if isinstance(field, (models.OneToOneField, models.ForeignKey, models.ManyToManyField, GenericRelation)):
        if field.rel.to in checked_models:
            return depends
        checked_models.add(field.rel.to)
        depends.add(field.rel.to)
        depends.update(field_dependencies(field.rel.to._meta.pk, checked_models))
        # Also include M2M throughs
        if isinstance(field, models.ManyToManyField):
            if field.rel.through:
                if hasattr(field.rel, "through_model"): # 1.1 and below
                    depends.add(field.rel.through_model)
                else:
                    depends.add(field.rel.through) # 1.2 and up
    return depends

### Prettyprinters

def pprint_frozen_models(models):
    return "{\n        %s\n    }" % ",\n        ".join([
        "%r: %s" % (name, pprint_fields(fields))
        for name, fields in sorted(models.items())
    ])

def pprint_fields(fields):
    return "{\n            %s\n        }" % ",\n            ".join([
        "%r: %r" % (name, defn)
        for name, defn in sorted(fields.items())
    ])

### Output sanitisers

USELESS_KEYWORDS = ["choices", "help_text", "upload_to", "verbose_name", "storage"]
USELESS_DB_KEYWORDS = ["related_name", "default"] # Important for ORM, not for DB.

def remove_useless_attributes(field, db=False):
    "Removes useless (for database) attributes from the field's defn."
    # Work out what to remove, and remove it.
    keywords = USELESS_KEYWORDS[:]
    if db:
        keywords += USELESS_DB_KEYWORDS[:]
    if field:
        for name in keywords:
            if name in field[2]:
                del field[2][name]
    return field

USELESS_META = ["verbose_name", "verbose_name_plural"]
def remove_useless_meta(meta):
    "Removes useless (for database) attributes from the table's meta."
    if meta:
        for name in USELESS_META:
            if name in meta:
                del meta[name]
    return meta<|endoftext|>


<commit_before>"""
Like the old south.modelsparser, but using introspection where possible
rather than direct inspection of models.py.
"""

import datetime
import re

from south.utils import get_attribute, auto_through

from django.db import models
from django.db.models.base import ModelBase, Model
from django.db.models.fields import NOT_PROVIDED
from django.conf import settings
from django.utils.functional import Promise
from django.contrib.contenttypes import generic
from django.utils.datastructures import SortedDict

NOISY = False

# Gives information about how to introspect certain fields.
# This is a list of triples; the first item is a list of fields it applies to,
# (note that isinstance is used, so superclasses are perfectly valid here)
# the second is a list of positional argument descriptors, and the third
# is a list of keyword argument descriptors.
# Descriptors are of the form:
#  [attrname, options]
# Where attrname is the attribute on the field to get the value from, and options
# is an optional dict.
#
# The introspector uses the combination of all matching entries, in order.
introspection_details = [
    (
        (models.Field, ),
        [],
        {
            "null": ["null", {"default": False}],
            "blank": ["blank", {"default": False, "ignore_if":"primary_key"}],
            "primary_key": ["primary_key", {"default": False}],
            "max_length": ["max_length", {"default": None}],
            "unique": ["_unique", {"default": False}],
            "db_index": ["db_index", {"default": False}],
            "default": ["default", {"default": NOT_PROVIDED}],
            "db_column": ["db_column", {"default": None}],
            "db_tablespace": ["db_tablespace", {"default": settings.DEFAULT_INDEX_TABLESPACE}],
        },
    ),
    (
        (models.ForeignKey, models.OneToOneField),
        [],
        {
            "to": ["rel.to", {}],
            "to_field": ["rel.field_name", {"default_attr": "rel.to._meta.pk.name"}],
            "related_name": ["rel.related_name", {"default": None}],
            "db_index": ["db_index", {"default": True}],
        },
    ),
    (
        (models.ManyToManyField,),
        [],
        {
            "to": ["rel.to", {}],
            "symmetrical": ["rel.symmetrical", {"default": True}],
            "related_name": ["rel.related_name", {"default": None}],
            # TODO: Kind of ugly to add this one-time-only option
            "through": ["rel.through", {"ignore_if_auto_through": True}],
        },
    ),
    (
        (models.DateField, models.TimeField),
        [],
        {
            "auto_now": ["auto_now", {"default": False}],
            "auto_now_add": ["auto_now_add", {"default": False}],
        },
    ),
    (
        (models.DecimalField, ),
        [],
        {
            "max_digits": ["max_digits", {"default": None}],
            "decimal_places": ["decimal_places", {"default": None}],
        },
    ),
    (
        (models.BooleanField, ),
        [],
        {
            "default": ["default", {"default": NOT_PROVIDED, "converter": bool}],
        },
    ),
    (
        (models.FilePathField, ),
        [],
        {
            "path": ["path", {"default": ''}],
            "match": ["match", {"default": None}],
            "recursive": ["recursive", {"default": False}],
        },
    ),
    (
        (generic.GenericRelation, ),
        [],
        {
            "to": ["rel.to", {}],
            "symmetrical": ["rel.symmetrical", {"default": True}],
            "object_id_field": ["object_id_field_name", {"default": "object_id"}],
            "content_type_field": ["content_type_field_name", {"default": "content_type"}],
            "blank": ["blank", {"default": True}],
        },
    ),
]

# Regexes of allowed field full paths
allowed_fields = [
    "^django\.db",
    "^django\.contrib\.contenttypes\.generic",
    "^django\.contrib\.localflavor",
]

# Regexes of ignored fields (custom fields which look like fields, but have no column behind them)
ignored_fields = []

# Similar, but for Meta, so just the inner level (kwds).
meta_details = {
    "db_table": ["db_table", {"default_attr_concat": ["%s_%s", "app_label", "module_name"]}],
    "db_tablespace": ["db_tablespace", {"default": settings.DEFAULT_TABLESPACE}],
    "unique_together": ["unique_together", {"default": []}],
}

# 2.4 compatability
any = lambda x: reduce(lambda y, z: y or z, x, False)

def add_introspection_rules(rules=[], patterns=[]):
    "Allows you to add some introspection rules at runtime, e.g. for 3rd party apps."
    assert isinstance(rules, (list, tuple))
    assert isinstance(patterns, (list, tuple))
    allowed_fields.extend(patterns)
    introspection_details.extend(rules)

def add_ignored_fields(patterns):
    "Allows you to add some ignore field patterns."
    assert isinstance(patterns, (list, tuple))
    ignored_fields.extend(patterns)

def can_ignore(field):
    """
    Returns True if we know for certain that we can ignore this field, False
    otherwise.
    """
    full_name = "%s.%s" % (field.__class__.__module__, field.__class__.__name__)
    for regex in ignored_fields:
        if re.match(regex, full_name):
            return True
    return False

def can_introspect(field):
    """
    Returns True if we are allowed to introspect this field, False otherwise.
    ('allowed' means 'in core'. Custom fields can declare they are introspectable
    by the default South rules by adding the attribute _south_introspects = True.)
    """
    # Check for special attribute
    if hasattr(field, "_south_introspects") and field._south_introspects:
        return True
    # Check it's an introspectable field
    full_name = "%s.%s" % (field.__class__.__module__, field.__class__.__name__)
    for regex in allowed_fields:
        if re.match(regex, full_name):
            return True
    return False

def matching_details(field):
    """
    Returns the union of all matching entries in introspection_details for the field.
    """
    our_args = []
    our_kwargs = {}
    for classes, args, kwargs in introspection_details:
        if any([isinstance(field, x) for x in classes]):
            our_args.extend(args)
            our_kwargs.update(kwargs)
    return our_args, our_kwargs

class IsDefault(Exception):
    """
    Exception for when a field contains its default value.
    """

def get_value(field, descriptor):
    """
    Gets an attribute value from a Field instance and formats it.
    """
    attrname, options = descriptor
    value = get_attribute(field, attrname)
    # Lazy-eval functions get eval'd.
    if isinstance(value, Promise):
        value = unicode(value)
    # If the value is the same as the default, omit it for clarity
    if "default" in options and value == options['default']:
        raise IsDefault
    # If there's an ignore_if, use it
    if "ignore_if" in options:
        if get_attribute(field, options['ignore_if']):
            raise IsDefault
    # If there's an ignore_if_auto_through which is True, use it
    if options.get("ignore_if_auto_through", False):
        if auto_through(field):
            raise IsDefault
    # Some default values need to be gotten from an attribute too.
    if "default_attr" in options:
        default_value = get_attribute(field, options['default_attr'])
        if value == default_value:
            raise IsDefault
    # Some are made from a formatting string and several attrs (e.g. db_table)
    if "default_attr_concat" in options:
        format, attrs = options['default_attr_concat'][0], options['default_attr_concat'][1:]
        default_value = format % tuple(map(lambda x: get_attribute(field, x), attrs))
        if value == default_value:
            raise IsDefault
    # Callables get called.
    if callable(value) and not isinstance(value, ModelBase):
        # Datetime.datetime.now is special, as we can access it from the eval
        # context (and because it changes all the time; people will file bugs otherwise).
        if value == datetime.datetime.now:
            return "datetime.datetime.now"
        if value == datetime.datetime.utcnow:
            return "datetime.datetime.utcnow"
        if value == datetime.date.today:
            return "datetime.date.today"
        # All other callables get called.
        value = value()
    # Models get their own special repr()
    if isinstance(value, ModelBase):
        # If it's a proxy model, follow it back to its non-proxy parent
        if getattr(value._meta, "proxy", False):
            value = value._meta.proxy_for_model
        return "orm['%s.%s']" % (value._meta.app_label, value._meta.object_name)
    # As do model instances
    if isinstance(value, Model):
        return "orm['%s.%s'].objects.get(pk=%r)" % (value.__class__._meta.app_label, value.__class__._meta.object_name, value.pk)
    # Now, apply the converter func if there is one
    if "converter" in options:
        value = options['converter'](value)
    # Return the final value
    return repr(value)

def introspector(field):
    """
    Given a field, introspects its definition triple.
    """
    arg_defs, kwarg_defs = matching_details(field)
    args = []
    kwargs = {}
    # For each argument, use the descriptor to get the real value.
    for defn in arg_defs:
        try:
            args.append(get_value(field, defn))
        except IsDefault:
            pass
    for kwd, defn in kwarg_defs.items():
        try:
            kwargs[kwd] = get_value(field, defn)
        except IsDefault:
            pass
    return args, kwargs

def get_model_fields(model, m2m=False):
    """
    Given a model class, returns a dict of {field_name: field_triple} defs.
    """

    field_defs = SortedDict()
    inherited_fields = {}

    # Go through all bases (that are themselves models, but not Model)
    for base in model.__bases__:
        if base != models.Model and issubclass(base, models.Model):
            if not base._meta.abstract:
                # Looks like we need their fields, Ma.
                inherited_fields.update(get_model_fields(base))

    # Now, go through all the fields and try to get their definition
    source = model._meta.local_fields[:]
    if m2m:
        source += model._meta.local_many_to_many

    for field in source:
        # Can we ignore it completely?
        if can_ignore(field):
            continue
        # Does it define a south_field_triple method?
        if hasattr(field, "south_field_triple"):
            if NOISY:
                print " ( Nativing field: %s" % field.name
            field_defs[field.name] = field.south_field_triple()
        # Can we introspect it?
        elif can_introspect(field):
            # Get the full field class path.
            field_class = field.__class__.__module__ + "." + field.__class__.__name__
            # Run this field through the introspector
            args, kwargs = introspector(field)
            # That's our definition!
            field_defs[field.name] = (field_class, args, kwargs)
        # Shucks, no definition!
        else:
            if NOISY:
                print " ( Nodefing field: %s" % field.name
            field_defs[field.name] = None

    return field_defs

def get_model_meta(model):
    """
    Given a model class, will return the dict representing the Meta class.
    """

    # Get the introspected attributes
    meta_def = {}
    for kwd, defn in meta_details.items():
        try:
            meta_def[kwd] = get_value(model._meta, defn)
        except IsDefault:
            pass

    return meta_def

# Now, load the built-in South introspection plugins
import south.introspection_plugins
<commit_msg>Fixing #347: Freezing of decimal values<commit_after>"""
Like the old south.modelsparser, but using introspection where possible
rather than direct inspection of models.py.
"""

import datetime
import re
import decimal

from south.utils import get_attribute, auto_through

from django.db import models
from django.db.models.base import ModelBase, Model
from django.db.models.fields import NOT_PROVIDED
from django.conf import settings
from django.utils.functional import Promise
from django.contrib.contenttypes import generic
from django.utils.datastructures import SortedDict

NOISY = False

# Gives information about how to introspect certain fields.
# This is a list of triples; the first item is a list of fields it applies to,
# (note that isinstance is used, so superclasses are perfectly valid here)
# the second is a list of positional argument descriptors, and the third
# is a list of keyword argument descriptors.
# Descriptors are of the form:
#  [attrname, options]
# Where attrname is the attribute on the field to get the value from, and options
# is an optional dict.
#
# The introspector uses the combination of all matching entries, in order.
introspection_details = [
    (
        (models.Field, ),
        [],
        {
            "null": ["null", {"default": False}],
            "blank": ["blank", {"default": False, "ignore_if":"primary_key"}],
            "primary_key": ["primary_key", {"default": False}],
            "max_length": ["max_length", {"default": None}],
            "unique": ["_unique", {"default": False}],
            "db_index": ["db_index", {"default": False}],
            "default": ["default", {"default": NOT_PROVIDED}],
            "db_column": ["db_column", {"default": None}],
            "db_tablespace": ["db_tablespace", {"default": settings.DEFAULT_INDEX_TABLESPACE}],
        },
    ),
    (
        (models.ForeignKey, models.OneToOneField),
        [],
        {
            "to": ["rel.to", {}],
            "to_field": ["rel.field_name", {"default_attr": "rel.to._meta.pk.name"}],
            "related_name": ["rel.related_name", {"default": None}],
            "db_index": ["db_index", {"default": True}],
        },
    ),
    (
        (models.ManyToManyField,),
        [],
        {
            "to": ["rel.to", {}],
            "symmetrical": ["rel.symmetrical", {"default": True}],
            "related_name": ["rel.related_name", {"default": None}],
            # TODO: Kind of ugly to add this one-time-only option
            "through": ["rel.through", {"ignore_if_auto_through": True}],
        },
    ),
    (
        (models.DateField, models.TimeField),
        [],
        {
            "auto_now": ["auto_now", {"default": False}],
            "auto_now_add": ["auto_now_add", {"default": False}],
        },
    ),
    (
        (models.DecimalField, ),
        [],
        {
            "max_digits": ["max_digits", {"default": None}],
            "decimal_places": ["decimal_places", {"default": None}],
        },
    ),
    (
        (models.BooleanField, ),
        [],
        {
            "default": ["default", {"default": NOT_PROVIDED, "converter": bool}],
        },
    ),
    (
        (models.FilePathField, ),
        [],
        {
            "path": ["path", {"default": ''}],
            "match": ["match", {"default": None}],
            "recursive": ["recursive", {"default": False}],
        },
    ),
    (
        (generic.GenericRelation, ),
        [],
        {
            "to": ["rel.to", {}],
            "symmetrical": ["rel.symmetrical", {"default": True}],
            "object_id_field": ["object_id_field_name", {"default": "object_id"}],
            "content_type_field": ["content_type_field_name", {"default": "content_type"}],
            "blank": ["blank", {"default": True}],
        },
    ),
]

# Regexes of allowed field full paths
allowed_fields = [
    "^django\.db",
    "^django\.contrib\.contenttypes\.generic",
    "^django\.contrib\.localflavor",
]

# Regexes of ignored fields (custom fields which look like fields, but have no column behind them)
ignored_fields = []

# Similar, but for Meta, so just the inner level (kwds).
meta_details = {
    "db_table": ["db_table", {"default_attr_concat": ["%s_%s", "app_label", "module_name"]}],
    "db_tablespace": ["db_tablespace", {"default": settings.DEFAULT_TABLESPACE}],
    "unique_together": ["unique_together", {"default": []}],
}

# 2.4 compatability
any = lambda x: reduce(lambda y, z: y or z, x, False)

def add_introspection_rules(rules=[], patterns=[]):
    "Allows you to add some introspection rules at runtime, e.g. for 3rd party apps."
    assert isinstance(rules, (list, tuple))
    assert isinstance(patterns, (list, tuple))
    allowed_fields.extend(patterns)
    introspection_details.extend(rules)

def add_ignored_fields(patterns):
    "Allows you to add some ignore field patterns."
    assert isinstance(patterns, (list, tuple))
    ignored_fields.extend(patterns)

def can_ignore(field):
    """
    Returns True if we know for certain that we can ignore this field, False
    otherwise.
    """
    full_name = "%s.%s" % (field.__class__.__module__, field.__class__.__name__)
    for regex in ignored_fields:
        if re.match(regex, full_name):
            return True
    return False

def can_introspect(field):
    """
    Returns True if we are allowed to introspect this field, False otherwise.
    ('allowed' means 'in core'. Custom fields can declare they are introspectable
    by the default South rules by adding the attribute _south_introspects = True.)
    """
    # Check for special attribute
    if hasattr(field, "_south_introspects") and field._south_introspects:
        return True
    # Check it's an introspectable field
    full_name = "%s.%s" % (field.__class__.__module__, field.__class__.__name__)
    for regex in allowed_fields:
        if re.match(regex, full_name):
            return True
    return False

def matching_details(field):
    """
    Returns the union of all matching entries in introspection_details for the field.
    """
    our_args = []
    our_kwargs = {}
    for classes, args, kwargs in introspection_details:
        if any([isinstance(field, x) for x in classes]):
            our_args.extend(args)
            our_kwargs.update(kwargs)
    return our_args, our_kwargs

class IsDefault(Exception):
    """
    Exception for when a field contains its default value.
    """

def get_value(field, descriptor):
    """
    Gets an attribute value from a Field instance and formats it.
    """
    attrname, options = descriptor
    value = get_attribute(field, attrname)
    # Lazy-eval functions get eval'd.
    if isinstance(value, Promise):
        value = unicode(value)
    # If the value is the same as the default, omit it for clarity
    if "default" in options and value == options['default']:
        raise IsDefault
    # If there's an ignore_if, use it
    if "ignore_if" in options:
        if get_attribute(field, options['ignore_if']):
            raise IsDefault
    # If there's an ignore_if_auto_through which is True, use it
    if options.get("ignore_if_auto_through", False):
        if auto_through(field):
            raise IsDefault
    # Some default values need to be gotten from an attribute too.
    if "default_attr" in options:
        default_value = get_attribute(field, options['default_attr'])
        if value == default_value:
            raise IsDefault
    # Some are made from a formatting string and several attrs (e.g. db_table)
    if "default_attr_concat" in options:
        format, attrs = options['default_attr_concat'][0], options['default_attr_concat'][1:]
        default_value = format % tuple(map(lambda x: get_attribute(field, x), attrs))
        if value == default_value:
            raise IsDefault
    # Callables get called.
    if callable(value) and not isinstance(value, ModelBase):
        # Datetime.datetime.now is special, as we can access it from the eval
        # context (and because it changes all the time; people will file bugs otherwise).
        if value == datetime.datetime.now:
            return "datetime.datetime.now"
        if value == datetime.datetime.utcnow:
            return "datetime.datetime.utcnow"
        if value == datetime.date.today:
            return "datetime.date.today"
        # All other callables get called.
        value = value()
    # Models get their own special repr()
    if isinstance(value, ModelBase):
        # If it's a proxy model, follow it back to its non-proxy parent
        if getattr(value._meta, "proxy", False):
            value = value._meta.proxy_for_model
        return "orm['%s.%s']" % (value._meta.app_label, value._meta.object_name)
    # As do model instances
    if isinstance(value, Model):
        return "orm['%s.%s'].objects.get(pk=%r)" % (value.__class__._meta.app_label, value.__class__._meta.object_name, value.pk)
    # Make sure Decimal is converted down into a string
    if isinstance(value, decimal.Decimal):
        value = str(value)
    # Now, apply the converter func if there is one
    if "converter" in options:
        value = options['converter'](value)
    # Return the final value
    return repr(value)

def introspector(field):
    """
    Given a field, introspects its definition triple.
    """
    arg_defs, kwarg_defs = matching_details(field)
    args = []
    kwargs = {}
    # For each argument, use the descriptor to get the real value.
    for defn in arg_defs:
        try:
            args.append(get_value(field, defn))
        except IsDefault:
            pass
    for kwd, defn in kwarg_defs.items():
        try:
            kwargs[kwd] = get_value(field, defn)
        except IsDefault:
            pass
    return args, kwargs

def get_model_fields(model, m2m=False):
    """
    Given a model class, returns a dict of {field_name: field_triple} defs.
    """

    field_defs = SortedDict()
    inherited_fields = {}

    # Go through all bases (that are themselves models, but not Model)
    for base in model.__bases__:
        if base != models.Model and issubclass(base, models.Model):
            if not base._meta.abstract:
                # Looks like we need their fields, Ma.
                inherited_fields.update(get_model_fields(base))

    # Now, go through all the fields and try to get their definition
    source = model._meta.local_fields[:]
    if m2m:
        source += model._meta.local_many_to_many

    for field in source:
        # Can we ignore it completely?
        if can_ignore(field):
            continue
        # Does it define a south_field_triple method?
        if hasattr(field, "south_field_triple"):
            if NOISY:
                print " ( Nativing field: %s" % field.name
            field_defs[field.name] = field.south_field_triple()
        # Can we introspect it?
        elif can_introspect(field):
            # Get the full field class path.
            field_class = field.__class__.__module__ + "." + field.__class__.__name__
            # Run this field through the introspector
            args, kwargs = introspector(field)
            # That's our definition!
            field_defs[field.name] = (field_class, args, kwargs)
        # Shucks, no definition!
        else:
            if NOISY:
                print " ( Nodefing field: %s" % field.name
            field_defs[field.name] = None

    return field_defs

def get_model_meta(model):
    """
    Given a model class, will return the dict representing the Meta class.
    """

    # Get the introspected attributes
    meta_def = {}
    for kwd, defn in meta_details.items():
        try:
            meta_def[kwd] = get_value(model._meta, defn)
        except IsDefault:
            pass

    return meta_def

# Now, load the built-in South introspection plugins
import south.introspection_plugins
<|endoftext|>


<commit_before>"""
Like south.modelsparser, but using introspection where possible
rather than direct inspection of models.py.
"""

import modelsparser
from south.utils import get_attribute

from django.db import models
from django.contrib.localflavor import us
from django.db.models.base import ModelBase
from django.db.models.fields import NOT_PROVIDED
from django.conf import settings

NOISY = True

# Gives information about how to introspect certain fields.
# This is a list of triples; the first item is a list of fields it applies to,
# (note that isinstance is used, so superclasses are perfectly valid here)
# the second is a list of positional argument descriptors, and the third
# is a list of keyword argument descriptors.
# Descriptors are of the form:
#  [attrname, options]
# Where attrname is the attribute on the field to get the value from, and options
# is an optional dict.
#
# The introspector uses the combination of all matching entries, in order.
introspection_details = [
    (
        (models.Field, ),
        [],
        {
            "null": ["null", {"default": False}],
            "blank": ["blank", {"default": False}],
            "primary_key": ["primary_key", {"default": False}],
            "max_length": ["max_length", {"default": None}],
            "unique": ["_unique", {"default": False}],
            "db_index": ["db_index", {"default": False}],
            "default": ["default", {"default": NOT_PROVIDED}],
            "db_column": ["db_column", {"default": None}],
            "db_tablespace": ["db_tablespace", {"default": settings.DEFAULT_INDEX_TABLESPACE}],
        },
    ),
    (
        (models.ForeignKey, models.OneToOneField),
        [],
        {
            "to": ["rel.to", {}],
            "to_field": ["rel.field_name", {"default_attr": "rel.to._meta.pk.name"}],
            "related_name": ["rel.related_name", {"default": None}],
            "db_index": ["db_index", {"default": True}],
        },
    ),
    (
        (models.ManyToManyField,),
        [],
        {
            "to": ["rel.to", {}],
        },
    ),
    (
        (models.DateField, models.TimeField),
        [],
        {
            "auto_now": ["auto_now", {"default": False}],
            "auto_now_add": ["auto_now_add", {"default": False}],
        },
    ),
    (
        (models.DecimalField, ),
        [],
        {
            "max_digits": ["max_digits", {"default": None}],
            "decimal_places": ["decimal_places", {"default": None}],
        },
    ),
    (
        (models.FilePathField, ),
        [],
        {
            "path": ["path", {"default": ''}],
            "match": ["match", {"default": None}],
            "recursive": ["recursive", {"default": False}],
        },
    ),
]

# Similar, but for Meta, so just the inner level (kwds).
meta_details = {
    "db_table": ["db_table", {"default_attr_concat": ["%s_%s", "app_label", "module_name"]}],
    "db_tablespace": ["db_tablespace", {"default": settings.DEFAULT_TABLESPACE}],
    "unique_together": ["unique_together", {"default": []}],
}

# 2.4 compatability
any = lambda x: reduce(lambda y, z: y or z, x, False)

def can_introspect(field):
    """
    Returns True if we are allowed to introspect this field, False otherwise.
    ('allowed' means 'in core'. Custom fields can declare they are introspectable
    by the default South rules by adding the attribute _south_introspects = True.)
    """
    # Check for special attribute
    if hasattr(field, "_south_introspects") and field._south_introspects:
        return True
    # Check it's a core field (one I've written for)
    module = field.__class__.__module__
    return module.startswith("django.db") or module.startswith("django.contrib.gis") or module.startswith("django.contrib.localflavor")

def matching_details(field):
    """
    Returns the union of all matching entries in introspection_details for the field.
    """
    our_args = []
    our_kwargs = {}
    for classes, args, kwargs in introspection_details:
        if any([isinstance(field, x) for x in classes]):
            our_args.extend(args)
            our_kwargs.update(kwargs)
    return our_args, our_kwargs

class IsDefault(Exception):
    """
    Exception for when a field contains its default value.
    """

def get_value(field, descriptor):
    """
    Gets an attribute value from a Field instance and formats it.
    """
    attrname, options = descriptor
    value = get_attribute(field, attrname)
    # If the value is the same as the default, omit it for clarity
    if "default" in options and value == options['default']:
        raise IsDefault
    # Some default values need to be gotten from an attribute too.
    if "default_attr" in options:
        default_value = get_attribute(field, options['default_attr'])
        if value == default_value:
            raise IsDefault
    # Some are made from a formatting string and several attrs (e.g. db_table)
    if "default_attr_concat" in options:
        format, attrs = options['default_attr_concat'][0], options['default_attr_concat'][1:]
        default_value = format % tuple(map(lambda x: get_attribute(field, x), attrs))
        if value == default_value:
            raise IsDefault
    # Models get their own special repr()
    if type(value) is ModelBase:
        return "orm['%s.%s']" % (value._meta.app_label, value._meta.object_name)
    # Callables get called.
    elif callable(value):
        return repr(value())
    else:
        return repr(value)

def introspector(field):
    """
    Given a field, introspects its definition triple.
    """
    arg_defs, kwarg_defs = matching_details(field)
    args = []
    kwargs = {}
    # For each argument, use the descriptor to get the real value.
    for defn in arg_defs:
        try:
            args.append(get_value(field, defn))
        except IsDefault:
            pass
    for kwd, defn in kwarg_defs.items():
        try:
            kwargs[kwd] = get_value(field, defn)
        except IsDefault:
            pass
    return args, kwargs

def get_model_fields(model, m2m=False):
    """
    Given a model class, returns a dict of {field_name: field_triple} defs.
    """

    field_defs = {}
    inherited_fields = {}

    # Go through all bases (that are themselves models, but not Model)
    for base in model.__bases__:
        if base != models.Model and issubclass(base, models.Model):
            # Looks like we need their fields, Ma.
            inherited_fields.update(get_model_fields(base))

    # Now, ask the parser to have a look at this model too.
    parser_fields = modelsparser.get_model_fields(model, m2m) or {}

    # Now, go through all the fields and try to get their definition
    source = model._meta.local_fields[:]
    if m2m:
        source += model._meta.local_many_to_many

    for field in source:
        # Does it define a south_field_triple method?
        if hasattr(field, "south_field_triple"):
            if NOISY:
                print "Nativing field: %s" % field.name
            field_defs[field.name] = field.south_field_triple()
        # Can we introspect it?
        elif can_introspect(field):
            #if NOISY:
            #    print "Introspecting field: %s" % field.name
            # Get the full field class path.
            field_class = field.__class__.__module__ + "." + field.__class__.__name__
            # Run this field through the introspector
            args, kwargs = introspector(field)
            # That's our definition!
            field_defs[field.name] = (field_class, args, kwargs)
        # Hmph. Is it parseable?
        elif parser_fields.get(field.name, None):
            if NOISY:
                print "Parsing field: %s" % field.name
            field_defs[field.name] = parser_fields[field.name]
        # Shucks, no definition!
        else:
            if NOISY:
                print "Nodefing field: %s" % field.name
            field_defs[field.name] = None

    return field_defs

def get_model_meta(model):
    """
    Given a model class, will return the dict representing the Meta class.
    """

    # Get the introspected attributes
    meta_def = {}
    for kwd, defn in meta_details.items():
        try:
            meta_def[kwd] = get_value(model._meta, defn)
        except IsDefault:
            pass

    return meta_def<commit_msg>Fix for #193<commit_after>"""
Like south.modelsparser, but using introspection where possible
rather than direct inspection of models.py.
"""

import modelsparser
from south.utils import get_attribute

from django.db import models
from django.contrib.localflavor import us
from django.db.models.base import ModelBase
from django.db.models.fields import NOT_PROVIDED
from django.conf import settings

NOISY = True

# Gives information about how to introspect certain fields.
# This is a list of triples; the first item is a list of fields it applies to,
# (note that isinstance is used, so superclasses are perfectly valid here)
# the second is a list of positional argument descriptors, and the third
# is a list of keyword argument descriptors.
# Descriptors are of the form:
#  [attrname, options]
# Where attrname is the attribute on the field to get the value from, and options
# is an optional dict.
#
# The introspector uses the combination of all matching entries, in order.
introspection_details = [
    (
        (models.Field, ),
        [],
        {
            "null": ["null", {"default": False}],
            "blank": ["blank", {"default": False}],
            "primary_key": ["primary_key", {"default": False}],
            "max_length": ["max_length", {"default": None}],
            "unique": ["_unique", {"default": False}],
            "db_index": ["db_index", {"default": False}],
            "default": ["default", {"default": NOT_PROVIDED}],
            "db_column": ["db_column", {"default": None}],
            "db_tablespace": ["db_tablespace", {"default": settings.DEFAULT_INDEX_TABLESPACE}],
        },
    ),
    (
        (models.ForeignKey, models.OneToOneField),
        [],
        {
            "to": ["rel.to", {}],
            "to_field": ["rel.field_name", {"default_attr": "rel.to._meta.pk.name"}],
            "related_name": ["rel.related_name", {"default": None}],
            "db_index": ["db_index", {"default": True}],
        },
    ),
    (
        (models.ManyToManyField,),
        [],
        {
            "to": ["rel.to", {}],
        },
    ),
    (
        (models.DateField, models.TimeField),
        [],
        {
            "auto_now": ["auto_now", {"default": False}],
            "auto_now_add": ["auto_now_add", {"default": False}],
        },
    ),
    (
        (models.DecimalField, ),
        [],
        {
            "max_digits": ["max_digits", {"default": None}],
            "decimal_places": ["decimal_places", {"default": None}],
        },
    ),
    (
        (models.FilePathField, ),
        [],
        {
            "path": ["path", {"default": ''}],
            "match": ["match", {"default": None}],
            "recursive": ["recursive", {"default": False}],
        },
    ),
]

# Similar, but for Meta, so just the inner level (kwds).
meta_details = {
    "db_table": ["db_table", {"default_attr_concat": ["%s_%s", "app_label", "module_name"]}],
    "db_tablespace": ["db_tablespace", {"default": settings.DEFAULT_TABLESPACE}],
    "unique_together": ["unique_together", {"default": []}],
}

# 2.4 compatability
any = lambda x: reduce(lambda y, z: y or z, x, False)

def can_introspect(field):
    """
    Returns True if we are allowed to introspect this field, False otherwise.
    ('allowed' means 'in core'. Custom fields can declare they are introspectable
    by the default South rules by adding the attribute _south_introspects = True.)
    """
    # Check for special attribute
    if hasattr(field, "_south_introspects") and field._south_introspects:
        return True
    # Check it's a core field (one I've written for)
    module = field.__class__.__module__
    return module.startswith("django.db") or module.startswith("django.contrib.gis") or module.startswith("django.contrib.localflavor")

def matching_details(field):
    """
    Returns the union of all matching entries in introspection_details for the field.
    """
    our_args = []
    our_kwargs = {}
    for classes, args, kwargs in introspection_details:
        if any([isinstance(field, x) for x in classes]):
            our_args.extend(args)
            our_kwargs.update(kwargs)
    return our_args, our_kwargs

class IsDefault(Exception):
    """
    Exception for when a field contains its default value.
    """

def get_value(field, descriptor):
    """
    Gets an attribute value from a Field instance and formats it.
    """
    attrname, options = descriptor
    value = get_attribute(field, attrname)
    # If the value is the same as the default, omit it for clarity
    if "default" in options and value == options['default']:
        raise IsDefault
    # Some default values need to be gotten from an attribute too.
    if "default_attr" in options:
        default_value = get_attribute(field, options['default_attr'])
        if value == default_value:
            raise IsDefault
    # Some are made from a formatting string and several attrs (e.g. db_table)
    if "default_attr_concat" in options:
        format, attrs = options['default_attr_concat'][0], options['default_attr_concat'][1:]
        default_value = format % tuple(map(lambda x: get_attribute(field, x), attrs))
        if value == default_value:
            raise IsDefault
    # Models get their own special repr()
    if isinstance(value, ModelBase):
        return "orm['%s.%s']" % (value._meta.app_label, value._meta.object_name)
    # Callables get called.
    elif callable(value):
        return repr(value())
    else:
        return repr(value)

def introspector(field):
    """
    Given a field, introspects its definition triple.
    """
    arg_defs, kwarg_defs = matching_details(field)
    args = []
    kwargs = {}
    # For each argument, use the descriptor to get the real value.
    for defn in arg_defs:
        try:
            args.append(get_value(field, defn))
        except IsDefault:
            pass
    for kwd, defn in kwarg_defs.items():
        try:
            kwargs[kwd] = get_value(field, defn)
        except IsDefault:
            pass
    return args, kwargs

def get_model_fields(model, m2m=False):
    """
    Given a model class, returns a dict of {field_name: field_triple} defs.
    """

    field_defs = {}
    inherited_fields = {}

    # Go through all bases (that are themselves models, but not Model)
    for base in model.__bases__:
        if base != models.Model and issubclass(base, models.Model):
            # Looks like we need their fields, Ma.
            inherited_fields.update(get_model_fields(base))

    # Now, ask the parser to have a look at this model too.
    parser_fields = modelsparser.get_model_fields(model, m2m) or {}

    # Now, go through all the fields and try to get their definition
    source = model._meta.local_fields[:]
    if m2m:
        source += model._meta.local_many_to_many

    for field in source:
        # Does it define a south_field_triple method?
        if hasattr(field, "south_field_triple"):
            if NOISY:
                print "Nativing field: %s" % field.name
            field_defs[field.name] = field.south_field_triple()
        # Can we introspect it?
        elif can_introspect(field):
            #if NOISY:
            #    print "Introspecting field: %s" % field.name
            # Get the full field class path.
            field_class = field.__class__.__module__ + "." + field.__class__.__name__
            # Run this field through the introspector
            args, kwargs = introspector(field)
            # That's our definition!
            field_defs[field.name] = (field_class, args, kwargs)
        # Hmph. Is it parseable?
        elif parser_fields.get(field.name, None):
            if NOISY:
                print "Parsing field: %s" % field.name
            field_defs[field.name] = parser_fields[field.name]
        # Shucks, no definition!
        else:
            if NOISY:
                print "Nodefing field: %s" % field.name
            field_defs[field.name] = None

    return field_defs

def get_model_meta(model):
    """
    Given a model class, will return the dict representing the Meta class.
    """

    # Get the introspected attributes
    meta_def = {}
    for kwd, defn in meta_details.items():
        try:
            meta_def[kwd] = get_value(model._meta, defn)
        except IsDefault:
            pass

    return meta_def<|endoftext|>


<commit_before>import os
import logging
import requests
import ftplib
import concurrent.futures as cf
from parsl.executors.base import ParslExecutor
from parsl.data_provider.globus import get_globus
from parsl.app.app import App

logger = logging.getLogger(__name__)

class DataManager(ParslExecutor):
    """DataManager uses the familiar Executor interface, where staging tasks are submitted
    to it, and DataFutures are returned.
    """

    """
    In general a site where remote file is going to be stage in is unknown until
    Executer submits an app that depends on the file. However, in most practical
    cases, a site where an app is executed and a file needs to be staged in is
    known. Such cases should be detected by DataManager to optimize file
    transfers. Possible cases are:
    1. Config defines one site only.
    2. Config defines several sites but all of the sites share the filesystem /
       use the same Globus endpoint.
    3. Config defines several sites with different Globus endpoints but a user
       specified explicitely that apps must be executed on a particular site.
    """

    default_data_manager = None

    @classmethod
    def get_data_manager(cls, dfk=None, config=None):
        if not cls.default_data_manager or dfk:
            cls.default_data_manager = DataManager(dfk, config=config)
        return cls.default_data_manager

    def __init__(self, dfk, max_workers=10, config=None):
        """Initialize the DataManager.

        Kwargs:
           - max_workers (int) : Number of threads (Default=10)
           - config (dict): The config dict object for the site:

        """
        self._scaling_enabled = False
        self.executor = cf.ThreadPoolExecutor(max_workers=max_workers)

        self.dfk = dfk
        self.config = config
        if not self.config:
            self.config = {"sites": []}
        self.files = []
        self.globus = None

    def submit(self, *args, **kwargs):
        """Submit a staging app. All optimization should be here."""
        return self.executor.submit(*args, **kwargs)

    def scale_in(self, blocks, *args, **kwargs):
        pass

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

    def shutdown(self, block=False):
        """Shutdown the ThreadPool.

        Kwargs:
            - block (Bool): To block for confirmations or not

        """
        x = self.executor.shutdown(wait=block)
        logger.debug("Done with executor shutdown")
        return x

    def scaling_enabled(self):
        return self._scaling_enabled

    def add_file(self, file):
        if file.scheme == 'globus':
            if not self.globus:
                self.globus = get_globus()
            # keep a list of all remote files for optimization purposes (TODO)
            self.files.append(file)
            self._set_local_path(file)

    def _set_local_path(self, file):
        globus_ep = self._get_globus_site()
        file.local_path = os.path.join(
                globus_ep['working_dir'],
                file.filename)

    def _get_globus_site(self, site_name='all'):
        if isinstance(site_name, list):
            site_name = site_name[0]
        for s in self.config['sites']:
            if site_name is 'all' or s['site'] == site_name:
                if 'data' not in s:
                    continue
                data = s['data']
                if 'globus' not in data or 'working_dir' not in data:
                    continue
                globus_ep = data['globus']
                if 'endpoint_name' not in globus_ep:
                    continue
                endpoint_name = data['globus']['endpoint_name']
                working_dir = os.path.normpath(data['working_dir'])
                if 'endpoint_path' in globus_ep and 'local_path' in globus_ep:
                    endpoint_path = os.path.normpath(globus_ep['endpoint_path'])
                    local_path = os.path.normpath(globus_ep['local_path'])
                    common_path = os.path.commonpath((local_path, working_dir))
                    if local_path != common_path:
                        raise Exception('"local_path" must be equal or an absolute subpath of "working_dir"')
                    relative_path = os.path.relpath(working_dir, common_path)
                    endpoint_path = os.path.join(endpoint_path, relative_path)
                else:
                    endpoint_path = working_dir
                return {'site_name': s['site'],
                        'endpoint_name': endpoint_name,
                        'endpoint_path': endpoint_path,
                        'working_dir': working_dir}
        raise Exception('No site with a Globus endpoint and working_dir defined')

    def _get_working_dir(self, site_name):
        for s in self.config['sites']:
            if s['site'] == site_name:
                if 'data' not in s:
                    break
                data = s['data']
                if 'working_dir' not in data:
                    break
                return os.path.normpath(data['working_dir'])
        return None

    def stage_in(self, file, site_name):
        """Transport the file from the site of origin to the site.

        This function returns a DataFuture.

        Args:
            - self
            - file (File) : file to stage in
            - site_name (str) : a site the file is going to be staged in to.
                                If the site argument is not specified for a file
                                with 'globus' scheme, the file will be staged in to
                                the first site with the "globus" key in a config.
        """

        if file.scheme == 'file':
            stage_in_app = self._file_stage_in_app()
            app_fut = stage_in_app(outputs=[file])
            return app_fut._outputs[0]
        elif file.scheme == 'ftp':
            working_dir = self._get_working_dir(site_name)
            stage_in_app = self._ftp_stage_in_app(site_name=site_name)
            app_fut = stage_in_app(working_dir, outputs=[file])
            return app_fut._outputs[0]
        elif file.scheme == 'http' or file.scheme == 'https':
            working_dir = self._get_working_dir(site_name)
            stage_in_app = self._http_stage_in_app(site_name=site_name)
            app_fut = stage_in_app(working_dir, outputs=[file])
            return app_fut._outputs[0]
        elif file.scheme == 'globus':
            globus_ep = self._get_globus_site(site_name)
            stage_in_app = self._globus_stage_in_app()
            app_fut = stage_in_app(globus_ep, outputs=[file])
            return app_fut._outputs[0]

    def _file_stage_in_app(self):
        return App("python", self.dfk, sites=['data_manager'])(self._file_stage_in)

    def _file_stage_in(self, outputs=[]):
        pass

    def _ftp_stage_in_app(self, site_name):
        return App("python", self.dfk, sites=site_name)(self._ftp_stage_in)

    def _ftp_stage_in(self, working_dir, outputs=[]):
        file = outputs[0]
        if working_dir:
            os.makedirs(working_dir, exist_ok=True)
            file.local_path = os.path.join(working_dir, file.filename)
        else:
            file.local_path = file.filename
        with open(file.local_path, 'wb') as f:
            ftp = ftplib.FTP(file.netloc)
            ftp.login()
            ftp.cwd(os.path.dirname(file.path))
            ftp.retrbinary('RETR {}'.format(file.filename), f.write)
            ftp.quit()

    def _http_stage_in_app(self, site_name):
        return App("python", self.dfk, sites=site_name)(self._http_stage_in)

    def _http_stage_in(self, working_dir, outputs=[]):
        file = outputs[0]
        if working_dir:
            os.makedirs(working_dir, exist_ok=True)
            file.local_path = os.path.join(working_dir, file.filename)
        else:
            file.local_path = file.filename
        resp = requests.get(file.url, stream=True)
        with open(file.local_path, 'wb') as f:
            for chunk in resp.iter_content(chunk_size=1024):
                if chunk:
                    f.write(chunk)

    def _globus_stage_in_app(self):
        return App("python", self.dfk, sites=['data_manager'])(self._globus_stage_in)

    def _globus_stage_in(self, globus_ep, outputs=[]):
        file = outputs[0]
        file.local_path = os.path.join(
                globus_ep['working_dir'], file.filename)
        dst_path = os.path.join(
                globus_ep['endpoint_path'], file.filename)
        self.globus.transfer_file(
                file.netloc, globus_ep['endpoint_name'],
                file.path, dst_path)

    def stage_out(self, file, site_name=None):
        """Transport the file from the local filesystem to the remote Globus endpoint.

        This function returns a DataFuture.

        Args:
            - self
            - file (File) - file to stage out
            - site_name (str) - a name of a site the file is going to be staged out from.
                                If the site argument is not specified for a file
                                with 'globus' scheme, the file will be staged in to
                                the first site with the "globus" key in a config.
        """

        if file.scheme == 'file':
            stage_out_app = self._file_stage_out_app()
            return stage_out_app()
        elif file.scheme == 'http' or file.scheme == 'https':
            raise Exception('FTP file staging out is not supported')
        elif file.scheme == 'ftp':
            raise Exception('HTTP/HTTPS file staging out is not supported')
        elif file.scheme == 'globus':
            globus_ep = self._get_globus_site(site_name)
            stage_out_app = self._globus_stage_out_app()
            return stage_out_app(globus_ep, inputs=[file])

    def _file_stage_out_app(self):
        return App("python", self.dfk, sites=['data_manager'])(self._file_stage_out)

    def _file_stage_out(self):
        pass

    def _globus_stage_out_app(self):
        return App("python", self.dfk, sites=['data_manager'])(self._globus_stage_out)

    def _globus_stage_out(self, globus_ep, inputs=[]):
        file = inputs[0]
        src_path = os.path.join(
                globus_ep['endpoint_path'], file.filename)
        self.globus.transfer_file(
                globus_ep['endpoint_name'], file.netloc,
                src_path, file.path)
<commit_msg>Rename max_workers -> max_threads<commit_after>import os
import logging
import requests
import ftplib
import concurrent.futures as cf
from parsl.executors.base import ParslExecutor
from parsl.data_provider.globus import get_globus
from parsl.app.app import App

logger = logging.getLogger(__name__)

class DataManager(ParslExecutor):
    """DataManager uses the familiar Executor interface, where staging tasks are submitted
    to it, and DataFutures are returned.
    """

    """
    In general a site where remote file is going to be stage in is unknown until
    Executer submits an app that depends on the file. However, in most practical
    cases, a site where an app is executed and a file needs to be staged in is
    known. Such cases should be detected by DataManager to optimize file
    transfers. Possible cases are:
    1. Config defines one site only.
    2. Config defines several sites but all of the sites share the filesystem /
       use the same Globus endpoint.
    3. Config defines several sites with different Globus endpoints but a user
       specified explicitely that apps must be executed on a particular site.
    """

    default_data_manager = None

    @classmethod
    def get_data_manager(cls, dfk=None, config=None):
        if not cls.default_data_manager or dfk:
            cls.default_data_manager = DataManager(dfk, config=config)
        return cls.default_data_manager

    def __init__(self, dfk, max_threads=10, config=None):
        """Initialize the DataManager.

        Kwargs:
           - max_threads (int) : Number of threads (Default=10)
           - config (dict): The config dict object for the site:

        """
        self._scaling_enabled = False
        self.executor = cf.ThreadPoolExecutor(max_workers=max_threads)

        self.dfk = dfk
        self.config = config
        if not self.config:
            self.config = {"sites": []}
        self.files = []
        self.globus = None

    def submit(self, *args, **kwargs):
        """Submit a staging app. All optimization should be here."""
        return self.executor.submit(*args, **kwargs)

    def scale_in(self, blocks, *args, **kwargs):
        pass

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

    def shutdown(self, block=False):
        """Shutdown the ThreadPool.

        Kwargs:
            - block (Bool): To block for confirmations or not

        """
        x = self.executor.shutdown(wait=block)
        logger.debug("Done with executor shutdown")
        return x

    def scaling_enabled(self):
        return self._scaling_enabled

    def add_file(self, file):
        if file.scheme == 'globus':
            if not self.globus:
                self.globus = get_globus()
            # keep a list of all remote files for optimization purposes (TODO)
            self.files.append(file)
            self._set_local_path(file)

    def _set_local_path(self, file):
        globus_ep = self._get_globus_site()
        file.local_path = os.path.join(
                globus_ep['working_dir'],
                file.filename)

    def _get_globus_site(self, site_name='all'):
        if isinstance(site_name, list):
            site_name = site_name[0]
        for s in self.config['sites']:
            if site_name is 'all' or s['site'] == site_name:
                if 'data' not in s:
                    continue
                data = s['data']
                if 'globus' not in data or 'working_dir' not in data:
                    continue
                globus_ep = data['globus']
                if 'endpoint_name' not in globus_ep:
                    continue
                endpoint_name = data['globus']['endpoint_name']
                working_dir = os.path.normpath(data['working_dir'])
                if 'endpoint_path' in globus_ep and 'local_path' in globus_ep:
                    endpoint_path = os.path.normpath(globus_ep['endpoint_path'])
                    local_path = os.path.normpath(globus_ep['local_path'])
                    common_path = os.path.commonpath((local_path, working_dir))
                    if local_path != common_path:
                        raise Exception('"local_path" must be equal or an absolute subpath of "working_dir"')
                    relative_path = os.path.relpath(working_dir, common_path)
                    endpoint_path = os.path.join(endpoint_path, relative_path)
                else:
                    endpoint_path = working_dir
                return {'site_name': s['site'],
                        'endpoint_name': endpoint_name,
                        'endpoint_path': endpoint_path,
                        'working_dir': working_dir}
        raise Exception('No site with a Globus endpoint and working_dir defined')

    def _get_working_dir(self, site_name):
        for s in self.config['sites']:
            if s['site'] == site_name:
                if 'data' not in s:
                    break
                data = s['data']
                if 'working_dir' not in data:
                    break
                return os.path.normpath(data['working_dir'])
        return None

    def stage_in(self, file, site_name):
        """Transport the file from the site of origin to the site.

        This function returns a DataFuture.

        Args:
            - self
            - file (File) : file to stage in
            - site_name (str) : a site the file is going to be staged in to.
                                If the site argument is not specified for a file
                                with 'globus' scheme, the file will be staged in to
                                the first site with the "globus" key in a config.
        """

        if file.scheme == 'file':
            stage_in_app = self._file_stage_in_app()
            app_fut = stage_in_app(outputs=[file])
            return app_fut._outputs[0]
        elif file.scheme == 'ftp':
            working_dir = self._get_working_dir(site_name)
            stage_in_app = self._ftp_stage_in_app(site_name=site_name)
            app_fut = stage_in_app(working_dir, outputs=[file])
            return app_fut._outputs[0]
        elif file.scheme == 'http' or file.scheme == 'https':
            working_dir = self._get_working_dir(site_name)
            stage_in_app = self._http_stage_in_app(site_name=site_name)
            app_fut = stage_in_app(working_dir, outputs=[file])
            return app_fut._outputs[0]
        elif file.scheme == 'globus':
            globus_ep = self._get_globus_site(site_name)
            stage_in_app = self._globus_stage_in_app()
            app_fut = stage_in_app(globus_ep, outputs=[file])
            return app_fut._outputs[0]

    def _file_stage_in_app(self):
        return App("python", self.dfk, sites=['data_manager'])(self._file_stage_in)

    def _file_stage_in(self, outputs=[]):
        pass

    def _ftp_stage_in_app(self, site_name):
        return App("python", self.dfk, sites=site_name)(self._ftp_stage_in)

    def _ftp_stage_in(self, working_dir, outputs=[]):
        file = outputs[0]
        if working_dir:
            os.makedirs(working_dir, exist_ok=True)
            file.local_path = os.path.join(working_dir, file.filename)
        else:
            file.local_path = file.filename
        with open(file.local_path, 'wb') as f:
            ftp = ftplib.FTP(file.netloc)
            ftp.login()
            ftp.cwd(os.path.dirname(file.path))
            ftp.retrbinary('RETR {}'.format(file.filename), f.write)
            ftp.quit()

    def _http_stage_in_app(self, site_name):
        return App("python", self.dfk, sites=site_name)(self._http_stage_in)

    def _http_stage_in(self, working_dir, outputs=[]):
        file = outputs[0]
        if working_dir:
            os.makedirs(working_dir, exist_ok=True)
            file.local_path = os.path.join(working_dir, file.filename)
        else:
            file.local_path = file.filename
        resp = requests.get(file.url, stream=True)
        with open(file.local_path, 'wb') as f:
            for chunk in resp.iter_content(chunk_size=1024):
                if chunk:
                    f.write(chunk)

    def _globus_stage_in_app(self):
        return App("python", self.dfk, sites=['data_manager'])(self._globus_stage_in)

    def _globus_stage_in(self, globus_ep, outputs=[]):
        file = outputs[0]
        file.local_path = os.path.join(
                globus_ep['working_dir'], file.filename)
        dst_path = os.path.join(
                globus_ep['endpoint_path'], file.filename)
        self.globus.transfer_file(
                file.netloc, globus_ep['endpoint_name'],
                file.path, dst_path)

    def stage_out(self, file, site_name=None):
        """Transport the file from the local filesystem to the remote Globus endpoint.

        This function returns a DataFuture.

        Args:
            - self
            - file (File) - file to stage out
            - site_name (str) - a name of a site the file is going to be staged out from.
                                If the site argument is not specified for a file
                                with 'globus' scheme, the file will be staged in to
                                the first site with the "globus" key in a config.
        """

        if file.scheme == 'file':
            stage_out_app = self._file_stage_out_app()
            return stage_out_app()
        elif file.scheme == 'http' or file.scheme == 'https':
            raise Exception('FTP file staging out is not supported')
        elif file.scheme == 'ftp':
            raise Exception('HTTP/HTTPS file staging out is not supported')
        elif file.scheme == 'globus':
            globus_ep = self._get_globus_site(site_name)
            stage_out_app = self._globus_stage_out_app()
            return stage_out_app(globus_ep, inputs=[file])

    def _file_stage_out_app(self):
        return App("python", self.dfk, sites=['data_manager'])(self._file_stage_out)

    def _file_stage_out(self):
        pass

    def _globus_stage_out_app(self):
        return App("python", self.dfk, sites=['data_manager'])(self._globus_stage_out)

    def _globus_stage_out(self, globus_ep, inputs=[]):
        file = inputs[0]
        src_path = os.path.join(
                globus_ep['endpoint_path'], file.filename)
        self.globus.transfer_file(
                globus_ep['endpoint_name'], file.netloc,
                src_path, file.path)
<|endoftext|>


<commit_before>import threading
import sys
from queue import *

#from munkware.mwQueue import *

"""

try:
	from munkware.mwQueue import *  # munkware
except:
	# NO MUNKWARE
	pass

# Esto es un prototipo de MessageList implementado con munkware,
# pero creo que no va, hay que mirarlo bien
class MWMessageList(BaseTransactionalQueue):
    def putAfter(self, item, block=True, timeout=None):
	self.avail_q_mutex.acquire()
	try:
	    if not block:
		if self._full():
		    raise Full
	    elif timeout is None:
		while self._full():
		    self.avail_q_mutex.wait()
	    else:
		if timeout < 0:
		    raise ValueError("'timeout' must be a positive number")
		endtime = _time() + timeout
		while self._full():
		    remaining = endtime - _time()
                    if remaining <= 0.0:
                        raise Full
                    self.avail_q_mutex.wait(remaining)
	    self._putAfter(item)
            self.avail_q_mutex.notify()
        finally:
            self.avail_q_mutex.release()

    def _putAfter(self, item):
        #self.queue.appendleft(item)
	self.put_commit(self.put(item))

class MessageList(queue):
    def putAfter(self, item, block=True, timeout=None):
        self.not_full.acquire()
        try:
            if not block:
                if self._full():
                    raise Full
            elif timeout is None:
                while self._full():
                    self.not_full.wait()
            else:
                if timeout < 0:
                    raise ValueError("'timeout' must be a positive number")
                endtime = _time() + timeout
                while self._full():
                    remaining = endtime - _time()
                    if remaining <= 0.0:
                        raise Full
                    self.not_full.wait(remaining)
            self._putAfter(item)
            self.not_empty.notify()
        finally:
            self.not_full.release()

    def _putAfter(self, item):
        self.queue.appendleft(item)
"""

class MessageReceiver(threading.Thread):
	def __init__(self):
		try:
			import psyco
			psyco.full()
		except ImportError:
			pass
		threading.Thread.__init__(self)
		#self.__messages = MessageList(0)
		self.__messages = Queue(0)
		#self.setDaemon(True)

	def __getMessage(self, block, tout):
		try:
			#if block:
			#	block_int = 1
			#else:
			#	block_int = 0
			#item = self.__messages.get(block_int)#, tout)
			item = self.__messages.get(block, tout)
			#self.__messages.get_commit(item[0])
			#message = item[1]
			print ">>> __getMessage: SUCCESS " + str(item)
		except Empty:
			message = None
			#print "MESSAGE = None - Empty "+str(tout)
			print ">>> __getMessage: EMPTY"
		except:
			message = None
			#time.sleep(1)
			#print "MESSAGE = None - otra.", sys.exc_info()[0]
			print ">>> __getMessage: FUCKING EXCEPTION"

		return message
	"""
	def receive(self):
		#returns a message if available
		#else returns None
		return self.__getMessage(False, None)
	"""
	def blockingReceive(self, time_seg = None):
		"""
		waits for a message during time_seg
		if time_seg == None waits until a message is received
		if no message is received returns None
		"""
		print ">>> blockingReceive time_seg = " + str(time_seg)
		return self.__getMessage(True, time_seg)

	def postMessage(self, message):
		if (message != None):
			#self.__messages.put_commit(self.__messages.put(message,block=True))
			self.__messages.put(message,block=True)
			print ">>>>>MSG posteado DE VERDAD: " + str(message.getContent())
		return True

	"""
	def kk(self, s=""):
		print s + "QSIZE: " + str(self.__messages.qsize())

	def putBackMessage(self, message):
		if (message != None):
			self.__messages.putAfter(message)
	"""
<commit_msg>packaging<commit_after>import threading
import sys
from queue import *

#from munkware.mwQueue import *

"""

try:
	from munkware.mwQueue import *  # munkware
except:
	# NO MUNKWARE
	pass

# Esto es un prototipo de MessageList implementado con munkware,
# pero creo que no va, hay que mirarlo bien
class MWMessageList(BaseTransactionalQueue):
    def putAfter(self, item, block=True, timeout=None):
	self.avail_q_mutex.acquire()
	try:
	    if not block:
		if self._full():
		    raise Full
	    elif timeout is None:
		while self._full():
		    self.avail_q_mutex.wait()
	    else:
		if timeout < 0:
		    raise ValueError("'timeout' must be a positive number")
		endtime = _time() + timeout
		while self._full():
		    remaining = endtime - _time()
                    if remaining <= 0.0:
                        raise Full
                    self.avail_q_mutex.wait(remaining)
	    self._putAfter(item)
            self.avail_q_mutex.notify()
        finally:
            self.avail_q_mutex.release()

    def _putAfter(self, item):
        #self.queue.appendleft(item)
	self.put_commit(self.put(item))

class MessageList(queue):
    def putAfter(self, item, block=True, timeout=None):
        self.not_full.acquire()
        try:
            if not block:
                if self._full():
                    raise Full
            elif timeout is None:
                while self._full():
                    self.not_full.wait()
            else:
                if timeout < 0:
                    raise ValueError("'timeout' must be a positive number")
                endtime = _time() + timeout
                while self._full():
                    remaining = endtime - _time()
                    if remaining <= 0.0:
                        raise Full
                    self.not_full.wait(remaining)
            self._putAfter(item)
            self.not_empty.notify()
        finally:
            self.not_full.release()

    def _putAfter(self, item):
        self.queue.appendleft(item)
"""

class MessageReceiver(threading.Thread):
	def __init__(self):
		try:
			import psyco
			psyco.full()
		except ImportError:
			pass
		threading.Thread.__init__(self)
		#self.__messages = MessageList(0)
		self.__messages = Queue(0)
		#self.setDaemon(True)

	def __getMessage(self, block, tout):
		try:
			#if block:
			#	block_int = 1
			#else:
			#	block_int = 0
			#item = self.__messages.get(block_int)#, tout)
			message = self.__messages.get(block, tout)
			#self.__messages.get_commit(item[0])
			#message = item[1]
			print ">>> __getMessage: SUCCESS " + str(message)
		except Empty:
			message = None
			#print "MESSAGE = None - Empty "+str(tout)
			print ">>> __getMessage: EMPTY"
		except:
			message = None
			#time.sleep(1)
			#print "MESSAGE = None - otra.", sys.exc_info()[0]
			print ">>> __getMessage: FUCKING EXCEPTION"

		return message
	"""
	def receive(self):
		#returns a message if available
		#else returns None
		return self.__getMessage(False, None)
	"""
	def blockingReceive(self, time_seg = None):
		"""
		waits for a message during time_seg
		if time_seg == None waits until a message is received
		if no message is received returns None
		"""
		print ">>> blockingReceive time_seg = " + str(time_seg)
		return self.__getMessage(True, time_seg)

	def postMessage(self, message):
		if (message != None):
			#self.__messages.put_commit(self.__messages.put(message,block=True))
			self.__messages.put(message,block=True)
			print ">>>>>MSG posteado DE VERDAD: " + str(message.getContent())
		return True

	"""
	def kk(self, s=""):
		print s + "QSIZE: " + str(self.__messages.qsize())

	def putBackMessage(self, message):
		if (message != None):
			self.__messages.putAfter(message)
	"""
<|endoftext|>


<commit_before>
import pygame, math, random

def sign(num):
	if (num==0):
		return 0
	else:
		return num/abs(num)

class Actor:
	def __init__(self, window, game, x, y, name, speed = 1, max_speed = 12, max_fall = 20, gravity = 1.3, friction = 0.5):
		if name == "Player":
			self.height = 16*8
			self.jump_force = 45
		else:
			self.height = 128
			self.jump_force = 15

		self.window = window
		self.game = game

		self.width = 64
		self.rect = pygame.Rect(x, y, self.width, self.height)
		self.surface = pygame.Surface((self.rect.w, self.rect.h))
		self.speed = speed
		self.velocity_y = 0
		self.velocity_x = 0
		self.max_fall = max_fall
		self.max_speed = max_speed
		self.friction = friction
		self.gravity = gravity
		self.onGround = True
		self.name = name
		self.deathTimer = 0
		self.shouldFlip = False
		self.facing = 'right'
		self.changeDirection = 0
		self.direction = 1
		self.fightTimer = 0
		self.isAttacking = False
		self.wasRunning = False

	def movement(self):
		f = self.friction
		# if self.onGround:
		# 	f = self.friction / 4

		self.onGround = False
		self.rect.x += self.velocity_x
		self.collideX()
		self.rect.y += self.velocity_y
		self.collideY()

		self.velocity_y += self.gravity

		#Uncomment if it's time to dance!
		if (abs(self.velocity_x) < f / 2):
			self.velocity = 0

		if (abs(self.velocity_x) > 0):
			self.velocity_x -= f * sign(self.velocity_x)

		if (abs(self.velocity_x) > self.max_speed):
			self.velocity_x = self.max_speed * sign(self.velocity_x)

		if abs(self.velocity_y) > self.max_fall:
			self.velocity_y = self.max_fall * sign(self.velocity_y)

		#print(abs(self.velocity_x))
	def getInput(self):
		pressed = pygame.key.get_pressed()

		if pressed[pygame.K_a]:
			self.velocity_x -= self.speed

		if pressed[pygame.K_d]:
			self.velocity_x += self.speed

		if pressed[pygame.K_j]:
			self.fight()

		if pressed[pygame.K_SPACE]:
			self.jump()

	# I excluded a section about screenwidth and the extra life
	def fight(self):
		if (not self.isAttacking):
			self.fightTimer = 1

	def jump(self):
		if self.onGround:
			self.jump_force_adjusted = self.jump_force + abs(self.velocity_x) * 2
			print(self.jump_force_adjusted)
			self.velocity_y = -self.jump_force_adjusted

	def collideX(self):
		for wall in self.game.getCurrentLevel().getWalls():
			if self.rect.right+self.velocity_x > wall.rect.left and self.rect.left + self.velocity_x < wall.rect.right:
				if self.rect.bottom <= wall.rect.top and self.rect.bottom + self.velocity_y > wall.rect.top:
					self.velocity_y = 0
					self.rect.bottom = wall.rect.top
					self.onGround = True
				if self.rect.top >= wall.rect.bottom and self.rect.top + self.velocity_y < wall.rect.bottom:
					self.velocity_y = 0
					self.rect.top = wall.rect.bottom
	def collideY(self):
		for wall in self.game.getCurrentLevel().getWalls():
			if self.rect.top < wall.rect.bottom and self.rect.bottom  > wall.rect.top:
				if self.rect.right <= wall.rect.left and self.rect.right + self.velocity_x + 2 > wall.rect.left:
					self.velocity_x = 0
					self.rect.right = wall.rect.left - 2
				if self.rect.left >= wall.rect.right and self.rect.left + self.velocity_x - 1 <= wall.rect.right:
					self.velocity_x = 0
					self.rect.left = wall.rect.right+2

	def drawPlayer(self, cameraX, cameraY):
		# if (self.deathTimer > 0 and self.deathTimer %2 == 0):
		# 	self.deathTimer = self.deathTimer
		# if self.onGround and self.velocity_x == 0:
		# 	self.window.blit(self.game.playerBreath)
		if (self.deathTimer>0 and self.deathTimer%2 == 0):
			self.deathTimer = self.deathTimer
			# don't do anything, wait a frame before drawing

		else:

			if self.velocity_x < 0:
				self.shouldFlip = True
				self.direction = -1
			elif self.velocity_x > 0:
				self.shouldFlip = False
				self.direction = 1

			if (self.onGround and self.velocity_x == 0):
				# this is breath
				self.window.blit(pygame.transform.flip((self.game.playerBreath[self.game.animation]), self.shouldFlip, False), (self.rect.x-cameraX, self.rect.y-16-cameraY))
			elif (not self.onGround):
				self.window.blit(pygame.transform.flip((self.game.playerJump), self.shouldFlip, False), (self.rect.x-cameraX, self.rect.y-16-cameraY))
			elif (self.velocity_x > 0):
				self.window.blit(pygame.transform.flip((self.game.playerWalk[self.game.animation]), self.shouldFlip, False), (self.rect.x-cameraX, self.rect.y-16-cameraY))
			elif (self.velocity_x < 0):
				self.window.blit(pygame.transform.flip((self.game.playerWalk[3-self.game.animation]), self.shouldFlip, False), (self.rect.x-cameraX, self.rect.y-16-cameraY))
			else:
				self.window.blit(self.game.playerBreath[1], (self.rect.x-cameraX, self.rect.y-16-cameraY))

			if self.direction==1:
				self.window.blit(pygame.transform.flip((self.game.knife[math.floor(self.game.animation/2)]), self.shouldFlip, False), (self.rect.x-16-cameraX, self.rect.y-8-cameraY))
			else:
				if self.velocity_x < 0:
					self.window.blit(pygame.transform.flip((self.game.knife[1-math.floor(self.game.animation/2)]), self.shouldFlip, False), (self.rect.x-cameraX, self.rect.y-8-cameraY))
				else:
					self.window.blit(pygame.transform.flip((self.game.knife[math.floor(self.game.animation/2)]), self.shouldFlip, False), (self.rect.x-cameraX, self.rect.y-8-cameraY))

		# come back to this

	def drawEnemy(self, cameraX, cameraY, facing):
		if facing == 'right':
			enemyFlip = True
		else:
			enemyFlip = False

		if (self.velocity_x == 0):
			if self.wasRunning == True:
				self.rect.y -= 32
				self.wasRunning = False
			self.rect.height = 128
			self.window.blit(pygame.transform.flip(self.game.enemyBreath[self.game.animation], enemyFlip, False), (self.rect.x - cameraX, self.rect.y - cameraY))
		else:
			self.rect.height = 96
			self.wasRunning = True
			self.window.blit(pygame.transform.flip(self.game.enemyRun[self.game.animation], enemyFlip, False), (self.rect.x - cameraX, self.rect.y - cameraY))

	def AI(self, facing, playerX, playerY):
		# depends on what the type of creature is
		if self.name == "Ostrich":
			blockedRight = False
			blockedLeft = False
			for wall in self.game.getCurrentLevel().getWalls():
				if self.rect.top < wall.rect.bottom and self.rect.bottom > wall.rect.top:
					if self.rect.right + 10 <= wall.rect.left and self.rect.right + 80 >= wall.rect.left:
						blockedRight = True
					if self.rect.left + -10 > wall.rect.right and self.rect.left - 80 < wall.rect.right:
						blockedLeft = True
			if facing == 'right':
				if ((not blockedRight) and (abs(playerY - (self.rect.y + self.rect.height) / 2) < 300) and (0 < (playerX - (self.rect.x + self.rect.width / 2)) < 800)):
					print('wrk?')
					self.velocity_x = 13
				print((0 < (playerX - (self.rect.x + self.rect.width / 2)) < 200))
			if facing == 'left':
				if ((not blockedLeft) and (abs(playerY - (self.rect.y + self.rect.height) / 2) < 300) and (0 > (playerX - (self.rect.x + self.rect.width / 2)) > -800)):
					print('wrk?')
					self.velocity_x = -13
				print((0 < (playerX - (self.rect.x + self.rect.width / 2)) < 200))

	def die(self):
		self.deathTimer = 0
		if (self.deathTimer > 0):
			self.deathTimer -= 1
		if self.rect.y > self.game.getCurrentLevel().getLevelHeight() and self.deathTimer==0:
			self.deathTimer = 50
			self.rect.x = 32
			self.rect.y = 0
			self.game.life += 1
		else:
			pass
			for enemy in self.game.enemyList[self.game.levelCounter]:
				if self.rect.colliderect(enemy) and self.deathTimer == 0:
					self.deathTimer = 50
					print("We need to have the user move back to the respawn point!")
					self.rect.x = 32
					self.rect.y = 0
					self.game.life += 1

	def update(self, cameraX, cameraY):
		self.getInput()
		self.die()
		self.movement()
		self.drawPlayer(cameraX, cameraY)
		# print("Location: ", self.rect.x, self.rect.y)
		# print("Velocities: ", self.velocity_x, self.velocity_y)

	def updateEnemy(self, cameraX, cameraY, playerX, playerY):
		if self.changeDirection == 25:
			if random.randint(1, 2) == 1:
				self.facing = 'right'
			else:
				self.facing = 'left'
			self.changeDirection = 0
		else:
			self.changeDirection += 1
		self.movement()
		self.AI(self.facing, playerX, playerY)
		self.drawEnemy(cameraX, cameraY, self.facing)

<commit_msg>give the player health<commit_after>
import pygame, math, random

def sign(num):
	if (num==0):
		return 0
	else:
		return num/abs(num)

class Actor:
	def __init__(self, window, game, x, y, name, speed = 1, max_speed = 12, max_fall = 20, gravity = 1.3, friction = 0.5, health = 100):
		if name == "Player":
			self.height = 16*8
			self.jump_force = 45
		else:
			self.height = 128
			self.jump_force = 15

		self.window = window
		self.game = game

		self.width = 64
		self.rect = pygame.Rect(x, y, self.width, self.height)
		self.surface = pygame.Surface((self.rect.w, self.rect.h))
		self.speed = speed
		self.velocity_y = 0
		self.velocity_x = 0
		self.max_fall = max_fall
		self.max_speed = max_speed
		self.friction = friction
		self.gravity = gravity
		self.onGround = True
		self.name = name
		self.deathTimer = 0
		self.shouldFlip = False
		self.facing = 'right'
		self.changeDirection = 0
		self.direction = 1
		self.fightTimer = 0
		self.isAttacking = False
		self.wasRunning = False
		self.health = health
		self.deathTimer = 0

	def movement(self):
		f = self.friction
		# if self.onGround:
		# 	f = self.friction / 4

		self.onGround = False
		self.rect.x += self.velocity_x
		self.collideX()
		self.rect.y += self.velocity_y
		self.collideY()

		self.velocity_y += self.gravity

		#Uncomment if it's time to dance!
		if (abs(self.velocity_x) < f / 2):
			self.velocity = 0

		if (abs(self.velocity_x) > 0):
			self.velocity_x -= f * sign(self.velocity_x)

		if (abs(self.velocity_x) > self.max_speed):
			self.velocity_x = self.max_speed * sign(self.velocity_x)

		if abs(self.velocity_y) > self.max_fall:
			self.velocity_y = self.max_fall * sign(self.velocity_y)

		#print(abs(self.velocity_x))
	def getInput(self):
		pressed = pygame.key.get_pressed()

		if pressed[pygame.K_a]:
			self.velocity_x -= self.speed

		if pressed[pygame.K_d]:
			self.velocity_x += self.speed

		if pressed[pygame.K_j]:
			self.fight()

		if pressed[pygame.K_SPACE]:
			self.jump()

	# I excluded a section about screenwidth and the extra life
	def fight(self):
		if (not self.isAttacking):
			self.fightTimer = 1

	def jump(self):
		if self.onGround:
			self.jump_force_adjusted = self.jump_force + abs(self.velocity_x) * 2
			print(self.jump_force_adjusted)
			self.velocity_y = -self.jump_force_adjusted

	def collideX(self):
		for wall in self.game.getCurrentLevel().getWalls():
			if self.rect.right+self.velocity_x > wall.rect.left and self.rect.left + self.velocity_x < wall.rect.right:
				if self.rect.bottom <= wall.rect.top and self.rect.bottom + self.velocity_y > wall.rect.top:
					self.velocity_y = 0
					self.rect.bottom = wall.rect.top
					self.onGround = True
				if self.rect.top >= wall.rect.bottom and self.rect.top + self.velocity_y < wall.rect.bottom:
					self.velocity_y = 0
					self.rect.top = wall.rect.bottom
	def collideY(self):
		for wall in self.game.getCurrentLevel().getWalls():
			if self.rect.top < wall.rect.bottom and self.rect.bottom  > wall.rect.top:
				if self.rect.right <= wall.rect.left and self.rect.right + self.velocity_x + 2 > wall.rect.left:
					self.velocity_x = 0
					self.rect.right = wall.rect.left - 2
				if self.rect.left >= wall.rect.right and self.rect.left + self.velocity_x - 1 <= wall.rect.right:
					self.velocity_x = 0
					self.rect.left = wall.rect.right+2

	def drawPlayer(self, cameraX, cameraY):
		# if (self.deathTimer > 0 and self.deathTimer %2 == 0):
		# 	self.deathTimer = self.deathTimer
		# if self.onGround and self.velocity_x == 0:
		# 	self.window.blit(self.game.playerBreath)
		if (self.deathTimer>0 and self.deathTimer%2 == 0):
			self.deathTimer = self.deathTimer
			# don't do anything, wait a frame before drawing

		else:

			if self.velocity_x < 0:
				self.shouldFlip = True
				self.direction = -1
			elif self.velocity_x > 0:
				self.shouldFlip = False
				self.direction = 1

			if (self.onGround and self.velocity_x == 0):
				# this is breath
				self.window.blit(pygame.transform.flip((self.game.playerBreath[self.game.animation]), self.shouldFlip, False), (self.rect.x-cameraX, self.rect.y-16-cameraY))
			elif (not self.onGround):
				self.window.blit(pygame.transform.flip((self.game.playerJump), self.shouldFlip, False), (self.rect.x-cameraX, self.rect.y-16-cameraY))
			elif (self.velocity_x > 0):
				self.window.blit(pygame.transform.flip((self.game.playerWalk[self.game.animation]), self.shouldFlip, False), (self.rect.x-cameraX, self.rect.y-16-cameraY))
			elif (self.velocity_x < 0):
				self.window.blit(pygame.transform.flip((self.game.playerWalk[3-self.game.animation]), self.shouldFlip, False), (self.rect.x-cameraX, self.rect.y-16-cameraY))
			else:
				self.window.blit(self.game.playerBreath[1], (self.rect.x-cameraX, self.rect.y-16-cameraY))

			if self.direction==1:
				self.window.blit(pygame.transform.flip((self.game.knife[math.floor(self.game.animation/2)]), self.shouldFlip, False), (self.rect.x-16-cameraX, self.rect.y-8-cameraY))
			else:
				if self.velocity_x < 0:
					self.window.blit(pygame.transform.flip((self.game.knife[1-math.floor(self.game.animation/2)]), self.shouldFlip, False), (self.rect.x-cameraX, self.rect.y-8-cameraY))
				else:
					self.window.blit(pygame.transform.flip((self.game.knife[math.floor(self.game.animation/2)]), self.shouldFlip, False), (self.rect.x-cameraX, self.rect.y-8-cameraY))

		# come back to this

	def drawEnemy(self, cameraX, cameraY, facing):
		if facing == 'right':
			enemyFlip = True
		else:
			enemyFlip = False

		if (self.velocity_x == 0):
			if self.wasRunning == True:
				self.rect.y -= 32
				self.wasRunning = False
			self.rect.height = 128
			self.window.blit(pygame.transform.flip(self.game.enemyBreath[self.game.animation], enemyFlip, False), (self.rect.x - cameraX, self.rect.y - cameraY))
		else:
			self.rect.height = 96
			self.wasRunning = True
			self.window.blit(pygame.transform.flip(self.game.enemyRun[self.game.animation], enemyFlip, False), (self.rect.x - cameraX, self.rect.y - cameraY))

	def AI(self, facing, playerX, playerY):
		# depends on what the type of creature is
		if self.name == "Ostrich":
			blockedRight = False
			blockedLeft = False
			for wall in self.game.getCurrentLevel().getWalls():
				if self.rect.top < wall.rect.bottom and self.rect.bottom > wall.rect.top:
					if self.rect.right + 10 <= wall.rect.left and self.rect.right + 80 >= wall.rect.left:
						blockedRight = True
					if self.rect.left + -10 > wall.rect.right and self.rect.left - 80 < wall.rect.right:
						blockedLeft = True
			if facing == 'right':
				if ((not blockedRight) and (abs(playerY - (self.rect.y + self.rect.height) / 2) < 300) and (0 < (playerX - (self.rect.x + self.rect.width / 2)) < 800)):
					#print('wrk?')
					self.velocity_x = 13
				#print((0 < (playerX - (self.rect.x + self.rect.width / 2)) < 200))
			if facing == 'left':
				if ((not blockedLeft) and (abs(playerY - (self.rect.y + self.rect.height) / 2) < 300) and (0 > (playerX - (self.rect.x + self.rect.width / 2)) > -800)):
					#print('wrk?')
					self.velocity_x = -13
				#print((0 < (playerX - (self.rect.x + self.rect.width / 2)) < 200))

	def die(self):
		if (self.deathTimer > 0):
			self.deathTimer -= 1
		if self.rect.y > self.game.getCurrentLevel().getLevelHeight() and self.deathTimer==0:
			self.deathTimer = 100
			self.rect.x = 32
			self.rect.y = 0
			self.game.life += 1
		else:
			for enemy in self.game.enemyList[self.game.levelCounter]:
				if self.rect.colliderect(enemy) and self.deathTimer == 0:
					self.health -= 20
					print(self.health)
					if self.health <= 0 and self.deathTimer == 0:
						self.deathTimer = 100
						print("We need to have the user move back to the respawn point!")
						self.rect.x = 32
						self.rect.y = 0
						self.health = 100
					self.deathTimer = 100

	def update(self, cameraX, cameraY):
		self.getInput()
		self.die()
		self.movement()
		self.drawPlayer(cameraX, cameraY)
		#print(self.health)
		# print("Location: ", self.rect.x, self.rect.y)
		# print("Velocities: ", self.velocity_x, self.velocity_y)

	def updateEnemy(self, cameraX, cameraY, playerX, playerY):
		if self.changeDirection == 25:
			if random.randint(1, 2) == 1:
				self.facing = 'right'
			else:
				self.facing = 'left'
			self.changeDirection = 0
		else:
			self.changeDirection += 1
		self.movement()
		self.AI(self.facing, playerX, playerY)
		self.drawEnemy(cameraX, cameraY, self.facing)

<|endoftext|>