<commit_before># Copyright 2021 The Bazel Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Rules for defining default_java_toolchain"""

load("@rules_java//java:defs.bzl", "java_toolchain")

JDK8_JVM_OPTS = [
    "-Xbootclasspath/p:$(location @remote_java_tools//:javac_jar)",
]

# JVM options, without patching java.compiler and jdk.compiler modules.
BASE_JDK9_JVM_OPTS = [
    # Allow JavaBuilder to access internal javac APIs.
    "--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED",
    "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED",
    "--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED",
    "--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED",
    "--add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED",
    "--add-exports=jdk.compiler/com.sun.tools.javac.resources=ALL-UNNAMED",
    "--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED",
    "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED",
    "--add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED",
    "--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED",
    "--add-opens=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED",

    # quiet warnings from com.google.protobuf.UnsafeUtil,
    # see: https://github.com/google/protobuf/issues/3781
    # and: https://github.com/bazelbuild/bazel/issues/5599
    "--add-opens=java.base/java.nio=ALL-UNNAMED",
    "--add-opens=java.base/java.lang=ALL-UNNAMED",
]

JDK9_JVM_OPTS = BASE_JDK9_JVM_OPTS + [
    # override the javac in the JDK.
    "--patch-module=java.compiler=$(location @remote_java_tools//:java_compiler_jar)",
    "--patch-module=jdk.compiler=$(location @remote_java_tools//:jdk_compiler_jar)",
]

DEFAULT_JAVACOPTS = [
    "-XDskipDuplicateBridges=true",
    "-XDcompilePolicy=simple",
    "-g",
    "-parameters",
    # https://github.com/bazelbuild/java_tools/issues/51#issuecomment-927940699
    "-XepOpt:ReturnValueIgnored:ObjectMethods=false",
]

# java_toolchain parameters without specifying javac, java.compiler,
# jdk.compiler module, and jvm_opts
_BASE_TOOLCHAIN_CONFIGURATION = dict(
    forcibly_disable_header_compilation = False,
    genclass = ["@remote_java_tools//:GenClass"],
    header_compiler = ["@remote_java_tools//:TurbineDirect"],
    header_compiler_direct = ["@remote_java_tools//:TurbineDirect"],
    ijar = ["//toolchains:ijar"],
    javabuilder = ["@remote_java_tools//:JavaBuilder"],
    javac_supports_workers = True,
    jacocorunner = "@remote_java_tools//:jacoco_coverage_runner_filegroup",
    jvm_opts = BASE_JDK9_JVM_OPTS,
    misc = DEFAULT_JAVACOPTS,
    singlejar = ["//toolchains:singlejar"],
    # Code to enumerate target JVM boot classpath uses host JVM. Because
    # java_runtime-s are involved, its implementation is in @bazel_tools.
    bootclasspath = ["//toolchains:platformclasspath"],
    source_version = "8",
    target_version = "8",
    reduced_classpath_incompatible_processors = [
        "dagger.hilt.processor.internal.root.RootProcessor",  # see b/21307381
    ],
)

JVM8_TOOLCHAIN_CONFIGURATION = dict(
    tools = ["@remote_java_tools//:javac_jar"],
    jvm_opts = ["-Xbootclasspath/p:$(location @remote_java_tools//:javac_jar)"],
    java_runtime = "//toolchains:jdk_8",
)

DEFAULT_TOOLCHAIN_CONFIGURATION = dict(
    jvm_opts = [
        # Compact strings make JavaBuilder slightly slower.
        "-XX:-CompactStrings",
    ] + JDK9_JVM_OPTS,
    turbine_jvm_opts = [
        # Turbine is not a worker and parallel GC is faster for short-lived programs.
        "-XX:+UseParallelOldGC",
    ],
    tools = [
        "@remote_java_tools//:java_compiler_jar",
        "@remote_java_tools//:jdk_compiler_jar",
    ],
    java_runtime = "//toolchains:remote_jdk11",
)

# The 'vanilla' toolchain is an unsupported alternative to the default.
#
# It does not provide any of the following features:
#   * Error Prone
#   * Strict Java Deps
#   * Reduced Classpath Optimization
#
# It uses the version of internal javac from the `--host_javabase` JDK instead
# of providing a javac. Internal javac may not be source- or bug-compatible with
# the javac that is provided with other toolchains.
#
# However it does allow using a wider range of `--host_javabase`s, including
# versions newer than the current JDK.
VANILLA_TOOLCHAIN_CONFIGURATION = dict(
    javabuilder = ["@remote_java_tools//:VanillaJavaBuilder"],
    jvm_opts = [],
)

# The new toolchain is using all the pre-built tools, including
# singlejar and ijar, even on remote execution. This toolchain
# should be used only when host and execution platform are the
# same, otherwise the binaries will not work on the execution
# platform.
PREBUILT_TOOLCHAIN_CONFIGURATION = dict(
    jvm_opts = [
        # Compact strings make JavaBuilder slightly slower.
        "-XX:-CompactStrings",
    ] + JDK9_JVM_OPTS,
    turbine_jvm_opts = [
        # Turbine is not a worker and parallel GC is faster for short-lived programs.
        "-XX:+UseParallelOldGC",
    ],
    tools = [
        "@remote_java_tools//:java_compiler_jar",
        "@remote_java_tools//:jdk_compiler_jar",
    ],
    ijar = ["//toolchains:ijar_prebuilt_binary"],
    singlejar = ["//toolchains:prebuilt_singlejar"],
    java_runtime = "//toolchains:remote_jdk11",
)

# The new toolchain is using all the tools from sources.
NONPREBUILT_TOOLCHAIN_CONFIGURATION = dict(
    jvm_opts = [
        # Compact strings make JavaBuilder slightly slower.
        "-XX:-CompactStrings",
    ] + JDK9_JVM_OPTS,
    turbine_jvm_opts = [
        # Turbine is not a worker and parallel GC is faster for short-lived programs.
        "-XX:+UseParallelOldGC",
    ],
    tools = [
        "@remote_java_tools//:java_compiler_jar",
        "@remote_java_tools//:jdk_compiler_jar",
    ],
    ijar = ["@remote_java_tools//:ijar_cc_binary"],
    singlejar = ["@remote_java_tools//:singlejar_cc_bin"],
    java_runtime = "//toolchains:remote_jdk11",
)

def default_java_toolchain(name, configuration = DEFAULT_TOOLCHAIN_CONFIGURATION, toolchain_definition = True, **kwargs):
    """Defines a remote java_toolchain with appropriate defaults for Bazel.

    Args:
        name: The name of the toolchain
        configuration: Toolchain configuration
        toolchain_definition: Whether to define toolchain target and its config setting
        **kwargs: More arguments for the java_toolchain target
    """

    toolchain_args = dict(_BASE_TOOLCHAIN_CONFIGURATION)
    toolchain_args.update(configuration)
    toolchain_args.update(kwargs)
    java_toolchain(
        name = name,
        **toolchain_args
    )
    if toolchain_definition:
        native.config_setting(
            name = name + "_version_setting",
            values = {"java_language_version": toolchain_args["source_version"]},
            visibility = ["//visibility:private"],
        )
        native.toolchain(
            name = name + "_definition",
            toolchain_type = "@bazel_tools//tools/jdk:toolchain_type",
            target_settings = [name + "_version_setting"],
            toolchain = name,
        )

def java_runtime_files(name, srcs):
    """Copies the given sources out of the current Java runtime."""

    native.filegroup(
        name = name,
        srcs = srcs,
    )
    for src in srcs:
        native.genrule(
            name = "gen_%s" % src,
            srcs = ["//toolchains:current_java_runtime"],
            toolchains = ["//toolchains:current_java_runtime"],
            cmd = "cp $(JAVABASE)/%s $@" % src,
            outs = [src],
        )

def _bootclasspath_impl(ctx):
    host_javabase = ctx.attr.host_javabase[java_common.JavaRuntimeInfo]

    # explicitly list output files instead of using TreeArtifact to work around
    # https://github.com/bazelbuild/bazel/issues/6203
    classes = [
        "DumpPlatformClassPath.class",
    ]

    class_outputs = [
        ctx.actions.declare_file("%s_classes/%s" % (ctx.label.name, clazz))
        for clazz in classes
    ]

    args = ctx.actions.args()
    args.add("-source")
    args.add("8")
    args.add("-target")
    args.add("8")
    args.add("-Xlint:-options")
    args.add("-cp")
    args.add("%s/lib/tools.jar" % host_javabase.java_home)
    args.add("-d")
    args.add(class_outputs[0].dirname)
    args.add(ctx.file.src)

    ctx.actions.run(
        executable = "%s/bin/javac" % host_javabase.java_home,
        mnemonic = "JavaToolchainCompileClasses",
        inputs = [ctx.file.src] + ctx.files.host_javabase,
        outputs = class_outputs,
        arguments = [args],
    )

    bootclasspath = ctx.outputs.output_jar

    inputs = class_outputs + ctx.files.host_javabase

    args = ctx.actions.args()
    args.add("-XX:+IgnoreUnrecognizedVMOptions")
    args.add("--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED")
    args.add("--add-exports=jdk.compiler/com.sun.tools.javac.platform=ALL-UNNAMED")
    args.add("--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED")
    args.add_joined(
        "-cp",
        [class_outputs[0].dirname, "%s/lib/tools.jar" % host_javabase.java_home],
        join_with = ctx.configuration.host_path_separator,
    )
    args.add("DumpPlatformClassPath")
    args.add(bootclasspath)

    if ctx.attr.target_javabase:
        inputs.extend(ctx.files.target_javabase)
        args.add(ctx.attr.target_javabase[java_common.JavaRuntimeInfo].java_home)

    ctx.actions.run(
        executable = str(host_javabase.java_executable_exec_path),
        mnemonic = "JavaToolchainCompileBootClasspath",
        inputs = inputs,
        outputs = [bootclasspath],
        arguments = [args],
    )
    return [
        DefaultInfo(files = depset([bootclasspath])),
        OutputGroupInfo(jar = [bootclasspath]),
    ]

_bootclasspath = rule(
    implementation = _bootclasspath_impl,
    attrs = {
        "host_javabase": attr.label(
            cfg = "host",
            providers = [java_common.JavaRuntimeInfo],
        ),
        "output_jar": attr.output(mandatory = True),
        "src": attr.label(
            cfg = "host",
            allow_single_file = True,
        ),
        "target_javabase": attr.label(
            providers = [java_common.JavaRuntimeInfo],
        ),
    },
)

def bootclasspath(name, **kwargs):
    _bootclasspath(
        name = name,
        output_jar = name + ".jar",
        **kwargs
    )
<commit_msg>Remove `-XepOpt:ReturnValueIgnored:ObjectMethods=false`<commit_after># Copyright 2021 The Bazel Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Rules for defining default_java_toolchain"""

load("@rules_java//java:defs.bzl", "java_toolchain")

JDK8_JVM_OPTS = [
    "-Xbootclasspath/p:$(location @remote_java_tools//:javac_jar)",
]

# JVM options, without patching java.compiler and jdk.compiler modules.
BASE_JDK9_JVM_OPTS = [
    # Allow JavaBuilder to access internal javac APIs.
    "--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED",
    "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED",
    "--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED",
    "--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED",
    "--add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED",
    "--add-exports=jdk.compiler/com.sun.tools.javac.resources=ALL-UNNAMED",
    "--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED",
    "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED",
    "--add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED",
    "--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED",
    "--add-opens=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED",

    # quiet warnings from com.google.protobuf.UnsafeUtil,
    # see: https://github.com/google/protobuf/issues/3781
    # and: https://github.com/bazelbuild/bazel/issues/5599
    "--add-opens=java.base/java.nio=ALL-UNNAMED",
    "--add-opens=java.base/java.lang=ALL-UNNAMED",
]

JDK9_JVM_OPTS = BASE_JDK9_JVM_OPTS + [
    # override the javac in the JDK.
    "--patch-module=java.compiler=$(location @remote_java_tools//:java_compiler_jar)",
    "--patch-module=jdk.compiler=$(location @remote_java_tools//:jdk_compiler_jar)",
]

DEFAULT_JAVACOPTS = [
    "-XDskipDuplicateBridges=true",
    "-XDcompilePolicy=simple",
    "-g",
    "-parameters",
]

# java_toolchain parameters without specifying javac, java.compiler,
# jdk.compiler module, and jvm_opts
_BASE_TOOLCHAIN_CONFIGURATION = dict(
    forcibly_disable_header_compilation = False,
    genclass = ["@remote_java_tools//:GenClass"],
    header_compiler = ["@remote_java_tools//:TurbineDirect"],
    header_compiler_direct = ["@remote_java_tools//:TurbineDirect"],
    ijar = ["//toolchains:ijar"],
    javabuilder = ["@remote_java_tools//:JavaBuilder"],
    javac_supports_workers = True,
    jacocorunner = "@remote_java_tools//:jacoco_coverage_runner_filegroup",
    jvm_opts = BASE_JDK9_JVM_OPTS,
    misc = DEFAULT_JAVACOPTS,
    singlejar = ["//toolchains:singlejar"],
    # Code to enumerate target JVM boot classpath uses host JVM. Because
    # java_runtime-s are involved, its implementation is in @bazel_tools.
    bootclasspath = ["//toolchains:platformclasspath"],
    source_version = "8",
    target_version = "8",
    reduced_classpath_incompatible_processors = [
        "dagger.hilt.processor.internal.root.RootProcessor",  # see b/21307381
    ],
)

JVM8_TOOLCHAIN_CONFIGURATION = dict(
    tools = ["@remote_java_tools//:javac_jar"],
    jvm_opts = ["-Xbootclasspath/p:$(location @remote_java_tools//:javac_jar)"],
    java_runtime = "//toolchains:jdk_8",
)

DEFAULT_TOOLCHAIN_CONFIGURATION = dict(
    jvm_opts = [
        # Compact strings make JavaBuilder slightly slower.
        "-XX:-CompactStrings",
    ] + JDK9_JVM_OPTS,
    turbine_jvm_opts = [
        # Turbine is not a worker and parallel GC is faster for short-lived programs.
        "-XX:+UseParallelOldGC",
    ],
    tools = [
        "@remote_java_tools//:java_compiler_jar",
        "@remote_java_tools//:jdk_compiler_jar",
    ],
    java_runtime = "//toolchains:remote_jdk11",
)

# The 'vanilla' toolchain is an unsupported alternative to the default.
#
# It does not provide any of the following features:
#   * Error Prone
#   * Strict Java Deps
#   * Reduced Classpath Optimization
#
# It uses the version of internal javac from the `--host_javabase` JDK instead
# of providing a javac. Internal javac may not be source- or bug-compatible with
# the javac that is provided with other toolchains.
#
# However it does allow using a wider range of `--host_javabase`s, including
# versions newer than the current JDK.
VANILLA_TOOLCHAIN_CONFIGURATION = dict(
    javabuilder = ["@remote_java_tools//:VanillaJavaBuilder"],
    jvm_opts = [],
)

# The new toolchain is using all the pre-built tools, including
# singlejar and ijar, even on remote execution. This toolchain
# should be used only when host and execution platform are the
# same, otherwise the binaries will not work on the execution
# platform.
PREBUILT_TOOLCHAIN_CONFIGURATION = dict(
    jvm_opts = [
        # Compact strings make JavaBuilder slightly slower.
        "-XX:-CompactStrings",
    ] + JDK9_JVM_OPTS,
    turbine_jvm_opts = [
        # Turbine is not a worker and parallel GC is faster for short-lived programs.
        "-XX:+UseParallelOldGC",
    ],
    tools = [
        "@remote_java_tools//:java_compiler_jar",
        "@remote_java_tools//:jdk_compiler_jar",
    ],
    ijar = ["//toolchains:ijar_prebuilt_binary"],
    singlejar = ["//toolchains:prebuilt_singlejar"],
    java_runtime = "//toolchains:remote_jdk11",
)

# The new toolchain is using all the tools from sources.
NONPREBUILT_TOOLCHAIN_CONFIGURATION = dict(
    jvm_opts = [
        # Compact strings make JavaBuilder slightly slower.
        "-XX:-CompactStrings",
    ] + JDK9_JVM_OPTS,
    turbine_jvm_opts = [
        # Turbine is not a worker and parallel GC is faster for short-lived programs.
        "-XX:+UseParallelOldGC",
    ],
    tools = [
        "@remote_java_tools//:java_compiler_jar",
        "@remote_java_tools//:jdk_compiler_jar",
    ],
    ijar = ["@remote_java_tools//:ijar_cc_binary"],
    singlejar = ["@remote_java_tools//:singlejar_cc_bin"],
    java_runtime = "//toolchains:remote_jdk11",
)

def default_java_toolchain(name, configuration = DEFAULT_TOOLCHAIN_CONFIGURATION, toolchain_definition = True, **kwargs):
    """Defines a remote java_toolchain with appropriate defaults for Bazel.

    Args:
        name: The name of the toolchain
        configuration: Toolchain configuration
        toolchain_definition: Whether to define toolchain target and its config setting
        **kwargs: More arguments for the java_toolchain target
    """

    toolchain_args = dict(_BASE_TOOLCHAIN_CONFIGURATION)
    toolchain_args.update(configuration)
    toolchain_args.update(kwargs)
    java_toolchain(
        name = name,
        **toolchain_args
    )
    if toolchain_definition:
        native.config_setting(
            name = name + "_version_setting",
            values = {"java_language_version": toolchain_args["source_version"]},
            visibility = ["//visibility:private"],
        )
        native.toolchain(
            name = name + "_definition",
            toolchain_type = "@bazel_tools//tools/jdk:toolchain_type",
            target_settings = [name + "_version_setting"],
            toolchain = name,
        )

def java_runtime_files(name, srcs):
    """Copies the given sources out of the current Java runtime."""

    native.filegroup(
        name = name,
        srcs = srcs,
    )
    for src in srcs:
        native.genrule(
            name = "gen_%s" % src,
            srcs = ["//toolchains:current_java_runtime"],
            toolchains = ["//toolchains:current_java_runtime"],
            cmd = "cp $(JAVABASE)/%s $@" % src,
            outs = [src],
        )

def _bootclasspath_impl(ctx):
    host_javabase = ctx.attr.host_javabase[java_common.JavaRuntimeInfo]

    # explicitly list output files instead of using TreeArtifact to work around
    # https://github.com/bazelbuild/bazel/issues/6203
    classes = [
        "DumpPlatformClassPath.class",
    ]

    class_outputs = [
        ctx.actions.declare_file("%s_classes/%s" % (ctx.label.name, clazz))
        for clazz in classes
    ]

    args = ctx.actions.args()
    args.add("-source")
    args.add("8")
    args.add("-target")
    args.add("8")
    args.add("-Xlint:-options")
    args.add("-cp")
    args.add("%s/lib/tools.jar" % host_javabase.java_home)
    args.add("-d")
    args.add(class_outputs[0].dirname)
    args.add(ctx.file.src)

    ctx.actions.run(
        executable = "%s/bin/javac" % host_javabase.java_home,
        mnemonic = "JavaToolchainCompileClasses",
        inputs = [ctx.file.src] + ctx.files.host_javabase,
        outputs = class_outputs,
        arguments = [args],
    )

    bootclasspath = ctx.outputs.output_jar

    inputs = class_outputs + ctx.files.host_javabase

    args = ctx.actions.args()
    args.add("-XX:+IgnoreUnrecognizedVMOptions")
    args.add("--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED")
    args.add("--add-exports=jdk.compiler/com.sun.tools.javac.platform=ALL-UNNAMED")
    args.add("--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED")
    args.add_joined(
        "-cp",
        [class_outputs[0].dirname, "%s/lib/tools.jar" % host_javabase.java_home],
        join_with = ctx.configuration.host_path_separator,
    )
    args.add("DumpPlatformClassPath")
    args.add(bootclasspath)

    if ctx.attr.target_javabase:
        inputs.extend(ctx.files.target_javabase)
        args.add(ctx.attr.target_javabase[java_common.JavaRuntimeInfo].java_home)

    ctx.actions.run(
        executable = str(host_javabase.java_executable_exec_path),
        mnemonic = "JavaToolchainCompileBootClasspath",
        inputs = inputs,
        outputs = [bootclasspath],
        arguments = [args],
    )
    return [
        DefaultInfo(files = depset([bootclasspath])),
        OutputGroupInfo(jar = [bootclasspath]),
    ]

_bootclasspath = rule(
    implementation = _bootclasspath_impl,
    attrs = {
        "host_javabase": attr.label(
            cfg = "host",
            providers = [java_common.JavaRuntimeInfo],
        ),
        "output_jar": attr.output(mandatory = True),
        "src": attr.label(
            cfg = "host",
            allow_single_file = True,
        ),
        "target_javabase": attr.label(
            providers = [java_common.JavaRuntimeInfo],
        ),
    },
)

def bootclasspath(name, **kwargs):
    _bootclasspath(
        name = name,
        output_jar = name + ".jar",
        **kwargs
    )
<|endoftext|>


<commit_before>"""
This module exists to smooth out some of the differences between PySide and PyQt4:

* Automatically import either PyQt4 or PySide depending on availability
* Allow to import QtCore/QtGui pyqtgraph.Qt without specifying which Qt wrapper
  you want to use.
* Declare QtCore.Signal, .Slot in PyQt4
* Declare loadUiType function for Pyside

"""

import sys, re

PYSIDE = 0
PYQT4 = 1
PYQT5 = 2

USE_QT_PY = None

# Special code when running in sphinx mode
if 'sphinx' in sys.modules:
    class QtGui(object):
        class QDialog(object):
            pass
        class QMainWindow(object):
            pass
    class QtCore(object):
        class QObject(object):
            pass
        @classmethod
        def Signal(caller=1,argument=2):
            pass
        pass
    def loadUiType(str):
        return object, object
    USE_PYSIDE = False
else:
    ## Automatically determine whether to use PyQt or PySide.
    ## This is done by first checking to see whether one of the libraries
    ## is already imported. If not, then attempt to import PyQt4, then PySide.
    if 'PyQt4' in sys.modules:
        USE_QT_PY = PYQT4
    if 'PyQt5' in sys.modules:
        USE_QT_PY = PYQT5
    elif 'PySide' in sys.modules:
        USE_QT_PY = PYSIDE
    else:
        try:
            import PyQt4
            USE_QT_PY = PYQT4
        except ImportError:
            try:
                import PyQt5
                USE_QT_PY = PYQT5
            except ImportError:
                try:
                    import PySide
                    USE_QT_PY = PYSIDE
                except:
                    pass

    if USE_QT_PY == None:
        raise Exception("PyQtGraph requires one of PyQt4, PyQt5 or PySide; none of these packages could be imported.")

    if USE_QT_PY == PYSIDE:
        from PySide import QtGui, QtCore, QtOpenGL, QtSvg
        import PySide
        try:
            VERSION_INFO = 'PySide ' + PySide.__version__
        except TypeError:
            pass

        # Make a loadUiType function like PyQt has

        # Credit:
        # http://stackoverflow.com/questions/4442286/python-code-genration-with-pyside-uic/14195313#14195313

        def loadUiType(uiFile):
            """
            Pyside "loadUiType" command like PyQt4 has one, so we have to convert the ui file to py code in-memory first    and then execute it in a special frame to retrieve the form_class.
            """
            import pysideuic
            import xml.etree.ElementTree as xml
            from cStringIO import StringIO

            parsed = xml.parse(uiFile)
            widget_class = parsed.find('widget').get('class')
            form_class = parsed.find('class').text

            with open(uiFile, 'r') as f:
                o = StringIO()
                frame = {}

                pysideuic.compileUi(f, o, indent=0)
                pyc = compile(o.getvalue(), '<string>', 'exec')
                exec(pyc, frame)

                #Fetch the base_class and form class based on their type in the xml from designer
                form_class = frame['Ui_%s'%form_class]
                base_class = eval('QtGui.%s'%widget_class)

            return form_class, base_class

    elif USE_QT_PY == PYQT4:
        import sip
        sip.setapi('QString', 2)
        sip.setapi('QVariant', 2)

        from PyQt4 import QtGui, QtCore, uic
        try:
            from PyQt4 import QtSvg
        except ImportError:
            pass
        try:
            from PyQt4 import QtOpenGL
        except ImportError:
            pass

        loadUiType = uic.loadUiType

        QtCore.Signal = QtCore.pyqtSignal
        QtCore.Slot = QtCore.pyqtSlot
        try:
            VERSION_INFO = 'PyQt4 ' + QtCore.PYQT_VERSION_STR + ' Qt ' +  QtCore.QT_VERSION_STR
        except TypeError:
            pass

    elif USE_QT_PY == PYQT5:

        # We're using PyQt5 which has a different structure so we're going to use a shim to
        # recreate the Qt4 structure for Qt5
        from PyQt5 import QtGui, QtCore, QtWidgets, Qt, uic
        try:
            from PyQt5 import QtSvg
        except ImportError:
            pass
        try:
            from PyQt5 import QtOpenGL
        except ImportError:
            pass

        # Re-implement deprecated APIs
        def scale(self, sx, sy):
            self.setTransform(QtGui.QTransform.fromScale(sx, sy), True)
        QtWidgets.QGraphicsItem.scale = scale

        def rotate(self, angle):
            self.setRotation(self.rotation() + angle)
        QtWidgets.QGraphicsItem.rotate = rotate

        def translate(self, dx, dy):
            self.setTransform(QtGui.QTransform.fromTranslate(dx, dy), True)
        QtWidgets.QGraphicsItem.translate = translate

        def setMargin(self, i):
            self.setContentsMargins(i, i, i, i)
        QtWidgets.QGridLayout.setMargin = setMargin

        def setResizeMode(self, mode):
            self.setSectionResizeMode(mode)
        QtWidgets.QHeaderView.setResizeMode = setResizeMode

        QtGui.QApplication = QtWidgets.QApplication
        QtGui.QGraphicsScene = QtWidgets.QGraphicsScene
        QtGui.QGraphicsObject = QtWidgets.QGraphicsObject
        QtGui.QGraphicsWidget = QtWidgets.QGraphicsWidget

        QtGui.QApplication.setGraphicsSystem = None
        QtCore.Signal = Qt.pyqtSignal

        # Import all QtWidgets objects into QtGui
        for o in dir(QtWidgets):
            if o.startswith('Q'):
                setattr(QtGui, o, getattr(QtWidgets,o) )

    ## Make sure we have Qt >= 4.7
    versionReq = [4, 7]
    USE_PYSIDE = USE_QT_PY == PYSIDE # still needed internally elsewhere
    QtVersion = PySide.QtCore.__version__ if USE_QT_PY ==  PYSIDE else QtCore.QT_VERSION_STR
    try:
        m = re.match(r'(\d+)\.(\d+).*', QtVersion)
        if m is not None and list(map(int, m.groups())) < versionReq:
            print(list(map(int, m.groups())))
            raise Exception('Hummingbird requires Qt version >= %d.%d  (your version is %s)' % (versionReq[0], versionReq[1], QtVersion))
    except TypeError:
        pass
<commit_msg>Also need loadUiType for PyQt5<commit_after>"""
This module exists to smooth out some of the differences between PySide and PyQt4:

* Automatically import either PyQt4 or PySide depending on availability
* Allow to import QtCore/QtGui pyqtgraph.Qt without specifying which Qt wrapper
  you want to use.
* Declare QtCore.Signal, .Slot in PyQt4
* Declare loadUiType function for Pyside

"""

import sys, re

PYSIDE = 0
PYQT4 = 1
PYQT5 = 2

USE_QT_PY = None

# Special code when running in sphinx mode
if 'sphinx' in sys.modules:
    class QtGui(object):
        class QDialog(object):
            pass
        class QMainWindow(object):
            pass
    class QtCore(object):
        class QObject(object):
            pass
        @classmethod
        def Signal(caller=1,argument=2):
            pass
        pass
    def loadUiType(str):
        return object, object
    USE_PYSIDE = False
else:
    ## Automatically determine whether to use PyQt or PySide.
    ## This is done by first checking to see whether one of the libraries
    ## is already imported. If not, then attempt to import PyQt4, then PySide.
    if 'PyQt4' in sys.modules:
        USE_QT_PY = PYQT4
    if 'PyQt5' in sys.modules:
        USE_QT_PY = PYQT5
    elif 'PySide' in sys.modules:
        USE_QT_PY = PYSIDE
    else:
        try:
            import PyQt4
            USE_QT_PY = PYQT4
        except ImportError:
            try:
                import PyQt5
                USE_QT_PY = PYQT5
            except ImportError:
                try:
                    import PySide
                    USE_QT_PY = PYSIDE
                except:
                    pass

    if USE_QT_PY == None:
        raise Exception("PyQtGraph requires one of PyQt4, PyQt5 or PySide; none of these packages could be imported.")

    if USE_QT_PY == PYSIDE:
        from PySide import QtGui, QtCore, QtOpenGL, QtSvg
        import PySide
        try:
            VERSION_INFO = 'PySide ' + PySide.__version__
        except TypeError:
            pass

        # Make a loadUiType function like PyQt has

        # Credit:
        # http://stackoverflow.com/questions/4442286/python-code-genration-with-pyside-uic/14195313#14195313

        def loadUiType(uiFile):
            """
            Pyside "loadUiType" command like PyQt4 has one, so we have to convert the ui file to py code in-memory first    and then execute it in a special frame to retrieve the form_class.
            """
            import pysideuic
            import xml.etree.ElementTree as xml
            from cStringIO import StringIO

            parsed = xml.parse(uiFile)
            widget_class = parsed.find('widget').get('class')
            form_class = parsed.find('class').text

            with open(uiFile, 'r') as f:
                o = StringIO()
                frame = {}

                pysideuic.compileUi(f, o, indent=0)
                pyc = compile(o.getvalue(), '<string>', 'exec')
                exec(pyc, frame)

                #Fetch the base_class and form class based on their type in the xml from designer
                form_class = frame['Ui_%s'%form_class]
                base_class = eval('QtGui.%s'%widget_class)

            return form_class, base_class

    elif USE_QT_PY == PYQT4:
        import sip
        sip.setapi('QString', 2)
        sip.setapi('QVariant', 2)

        from PyQt4 import QtGui, QtCore, uic
        try:
            from PyQt4 import QtSvg
        except ImportError:
            pass
        try:
            from PyQt4 import QtOpenGL
        except ImportError:
            pass

        loadUiType = uic.loadUiType

        QtCore.Signal = QtCore.pyqtSignal
        QtCore.Slot = QtCore.pyqtSlot
        try:
            VERSION_INFO = 'PyQt4 ' + QtCore.PYQT_VERSION_STR + ' Qt ' +  QtCore.QT_VERSION_STR
        except TypeError:
            pass

    elif USE_QT_PY == PYQT5:

        # We're using PyQt5 which has a different structure so we're going to use a shim to
        # recreate the Qt4 structure for Qt5
        from PyQt5 import QtGui, QtCore, QtWidgets, Qt, uic
        try:
            from PyQt5 import QtSvg
        except ImportError:
            pass
        try:
            from PyQt5 import QtOpenGL
        except ImportError:
            pass

        loadUiType = uic.loadUiType

        # Re-implement deprecated APIs
        def scale(self, sx, sy):
            self.setTransform(QtGui.QTransform.fromScale(sx, sy), True)
        QtWidgets.QGraphicsItem.scale = scale

        def rotate(self, angle):
            self.setRotation(self.rotation() + angle)
        QtWidgets.QGraphicsItem.rotate = rotate

        def translate(self, dx, dy):
            self.setTransform(QtGui.QTransform.fromTranslate(dx, dy), True)
        QtWidgets.QGraphicsItem.translate = translate

        def setMargin(self, i):
            self.setContentsMargins(i, i, i, i)
        QtWidgets.QGridLayout.setMargin = setMargin

        def setResizeMode(self, mode):
            self.setSectionResizeMode(mode)
        QtWidgets.QHeaderView.setResizeMode = setResizeMode

        QtGui.QApplication = QtWidgets.QApplication
        QtGui.QGraphicsScene = QtWidgets.QGraphicsScene
        QtGui.QGraphicsObject = QtWidgets.QGraphicsObject
        QtGui.QGraphicsWidget = QtWidgets.QGraphicsWidget

        QtGui.QApplication.setGraphicsSystem = None
        QtCore.Signal = Qt.pyqtSignal

        # Import all QtWidgets objects into QtGui
        for o in dir(QtWidgets):
            if o.startswith('Q'):
                setattr(QtGui, o, getattr(QtWidgets,o) )

    ## Make sure we have Qt >= 4.7
    versionReq = [4, 7]
    USE_PYSIDE = USE_QT_PY == PYSIDE # still needed internally elsewhere
    QtVersion = PySide.QtCore.__version__ if USE_QT_PY ==  PYSIDE else QtCore.QT_VERSION_STR
    try:
        m = re.match(r'(\d+)\.(\d+).*', QtVersion)
        if m is not None and list(map(int, m.groups())) < versionReq:
            print(list(map(int, m.groups())))
            raise Exception('Hummingbird requires Qt version >= %d.%d  (your version is %s)' % (versionReq[0], versionReq[1], QtVersion))
    except TypeError:
        pass
<|endoftext|>


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

#   Copyright 2012 Tuukka Turto
#
#   This file is part of pyherc.
#
#   pyherc is free software: you can redistribute it and/or modify
#   it under the terms of the GNU General Public License as published by
#   the Free Software Foundation, either version 3 of the License, or
#   (at your option) any later version.
#
#   pyherc is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.
#
#   You should have received a copy of the GNU General Public License
#   along with pyherc.  If not, see <http://www.gnu.org/licenses/>.

"""
Module for poison
"""
from pyherc.aspects import Logged
from pyherc.rules.effects.effect import Effect

class Poison(Effect):
    """
    Class representing effects of poison
    """
    logged = Logged()

    @logged
    def __init__(self, duration, frequency, tick, damage, target):
        """
        Default constructor
        """
        super(Poison, self).__init__(duration, frequency, tick)
        self.damage = damage
        self.target = target

    @logged
    def do_trigger(self):
        """
        Triggers effects of the poison
        """
        self.target.hit_points = self.target.hit_points - self.damage
<commit_msg>character can now die of poison<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-

#   Copyright 2012 Tuukka Turto
#
#   This file is part of pyherc.
#
#   pyherc is free software: you can redistribute it and/or modify
#   it under the terms of the GNU General Public License as published by
#   the Free Software Foundation, either version 3 of the License, or
#   (at your option) any later version.
#
#   pyherc is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.
#
#   You should have received a copy of the GNU General Public License
#   along with pyherc.  If not, see <http://www.gnu.org/licenses/>.

"""
Module for poison
"""
from pyherc.aspects import Logged
from pyherc.rules.effects.effect import Effect
from pyherc.rules.ending import check_dying

class Poison(Effect):
    """
    Class representing effects of poison
    """
    logged = Logged()

    @logged
    def __init__(self, duration, frequency, tick, damage, target):
        """
        Default constructor
        """
        super(Poison, self).__init__(duration, frequency, tick)
        self.damage = damage
        self.target = target

    @logged
    def do_trigger(self):
        """
        Triggers effects of the poison
        """
        self.target.hit_points = self.target.hit_points - self.damage
        check_dying(model = self.target.model,
                    character = self.target,
                    death_params = None)
<|endoftext|>


<commit_before>from director import callbacks
from director.fieldcontainer import FieldContainer

import re
import numpy as np
from collections import OrderedDict

def cleanPropertyName(s):
    """
    Generate a valid python property name by replacing all non-alphanumeric characters with underscores and adding an initial underscore if the first character is a digit
    """
    return re.sub(r'\W|^(?=\d)','_',s).lower()  # \W matches non-alphanumeric, ^(?=\d) matches the first position if followed by a digit

class PropertyAttributes(FieldContainer):

    def __init__(self, **kwargs):

        self._add_fields(
          decimals = 5,
          minimum = -1e4,
          maximum = 1e4,
          singleStep = 1,
          hidden = False,
          enumNames = None,
          readOnly = False,
          )

        self._set_fields(**kwargs)

from PythonQt import QtGui

def fromQColor(propertyName, propertyValue):
    if isinstance(propertyValue, QtGui.QColor):
        return [propertyValue.red()/255.0, propertyValue.green()/255.0, propertyValue.blue()/255.0]
    else:
        return propertyValue

def toQProperty(propertyName, propertyValue):
    if 'color' in propertyName.lower() and isinstance(propertyValue, (list, tuple)) and len(propertyValue) == 3:
        return QtGui.QColor(propertyValue[0]*255.0, propertyValue[1]*255.0, propertyValue[2]*255.0)
    elif isinstance(propertyValue, np.float):
        return float(propertyValue)
    elif isinstance(propertyValue, (list, tuple, np.ndarray)) and len(propertyValue) and isinstance(propertyValue[0], np.float):
        return [float(x) for x in propertyValue]
    else:
        return propertyValue

class PropertySet(object):

    PROPERTY_CHANGED_SIGNAL = 'PROPERTY_CHANGED_SIGNAL'
    PROPERTY_ADDED_SIGNAL = 'PROPERTY_ADDED_SIGNAL'
    PROPERTY_ATTRIBUTE_CHANGED_SIGNAL = 'PROPERTY_ATTRIBUTE_CHANGED_SIGNAL'

    def __getstate__(self):
        d = dict(_properties=self._properties, _attributes=self._attributes)
        return d

    def __setstate__(self, state):
        self.__init__()
        attrs = state['_attributes']
        for propName, propValue in state['_properties'].iteritems():
            self.addProperty(propName, propValue, attributes=attrs.get(propName))

    def __init__(self):

        self.callbacks = callbacks.CallbackRegistry([self.PROPERTY_CHANGED_SIGNAL,
                                                     self.PROPERTY_ADDED_SIGNAL,
                                                     self.PROPERTY_ATTRIBUTE_CHANGED_SIGNAL])

        self._properties = OrderedDict()
        self._attributes = {}
        self._alternateNames = {}

    def propertyNames(self):
        return self._properties.keys()

    def hasProperty(self, propertyName):
        return propertyName in self._properties

    def assertProperty(self, propertyName):
        assert self.hasProperty(propertyName), "Missing property: {:s}".format(propertyName)

    def connectPropertyChanged(self, func):
        return self.callbacks.connect(self.PROPERTY_CHANGED_SIGNAL, func)

    def disconnectPropertyChanged(self, callbackId):
        self.callbacks.disconnect(callbackId)

    def connectPropertyAdded(self, func):
        return self.callbacks.connect(self.PROPERTY_ADDED_SIGNAL, func)

    def disconnectPropertyAdded(self, callbackId):
        self.callbacks.disconnect(callbackId)

    def connectPropertyAttributeChanged(self, func):
        return self.callbacks.connect(self.PROPERTY_ATTRIBUTE_CHANGED_SIGNAL, func)

    def disconnectPropertyAttributeChanged(self, callbackId):
        self.callbacks.disconnect(callbackId)

    def getProperty(self, propertyName):
        self.assertProperty(propertyName)
        return self._properties[propertyName]

    def getPropertyEnumValue(self, propertyName):
        self.assertProperty(propertyName)
        return self._attributes[propertyName].enumNames[self._properties[propertyName]]

    def removeProperty(self, propertyName):
        assert self.hasProperty(propertyName)
        alternateName = cleanPropertyName(propertyName)
        del self._alternateNames[alternateName]
        del self._properties[propertyName]
        del self._attributes[propertyName]

    def addProperty(self, propertyName, propertyValue, attributes=None):
        alternateName = cleanPropertyName(propertyName)
        if propertyName not in self._properties and alternateName in self._alternateNames:
            raise ValueError('Adding this property would conflict with a different existing property with alternate name {:s}'.format(alternateName))

        propertyValue = fromQColor(propertyName, propertyValue)

        self._alternateNames[alternateName] = propertyName
        self._properties[propertyName] = propertyValue
        self._attributes[propertyName] = attributes or PropertyAttributes()

        self.callbacks.process(self.PROPERTY_ADDED_SIGNAL, self, propertyName)

    def setPropertyIndex(self, propertyName, newIndex):
        assert self.hasProperty(propertyName)
        currentIndex = self._properties.keys().index(propertyName)
        inds = range(len(self._properties))
        inds.remove(currentIndex)
        inds.insert(newIndex, currentIndex)
        items = self._properties.items()
        self._properties = OrderedDict([items[i] for i in inds])

    def setProperty(self, propertyName, propertyValue):
        self.assertProperty(propertyName)
        propertyValue = fromQColor(propertyName, propertyValue)

        names = self.getPropertyAttribute(propertyName, 'enumNames')
        if names and type(propertyValue) != int:
            propertyValue = names.index(propertyValue)

        self.oldPropertyValue = (propertyName, self.getProperty(propertyName))
        self._properties[propertyName] = propertyValue
        self.oldPropertyValue = None
        self.callbacks.process(self.PROPERTY_CHANGED_SIGNAL, self, propertyName)

    def getPropertyAttribute(self, propertyName, propertyAttribute):
        self.assertProperty(propertyName)
        return getattr(self._attributes[propertyName], propertyAttribute)

    def setPropertyAttribute(self, propertyName, propertyAttribute, value):
        self.assertProperty(propertyName)
        attributes = self._attributes[propertyName]
        assert hasattr(attributes, propertyAttribute), "Missing attribute: {:s}".format(propertyAttribute)
        setattr(attributes, propertyAttribute, value)
        self.callbacks.process(self.PROPERTY_ATTRIBUTE_CHANGED_SIGNAL, self, propertyName, propertyAttribute)

    def __getattribute__(self, name):
        try:
            alternateNames = object.__getattribute__(self, '_alternateNames')
            if name in alternateNames:
                return object.__getattribute__(self, 'getProperty')(alternateNames[name])
            else:
                raise AttributeError()
        except AttributeError:
            return object.__getattribute__(self, name)

class PropertyPanelHelper(object):

    @staticmethod
    def addPropertiesToPanel(properties, panel, propertyNamesToAdd = None):

        for propertyName in properties.propertyNames():
            value = properties.getProperty(propertyName)
            attributes = properties._attributes[propertyName]

            if value is not None and not attributes.hidden:
                addThisProperty = True
                if (propertyNamesToAdd is not None):
                    if (propertyName not in propertyNamesToAdd):
                        addThisProperty = False

                if addThisProperty:
                    PropertyPanelHelper._addProperty(panel, propertyName, attributes, value)

    @staticmethod
    def onPropertyValueChanged(panel, properties, propertyName):
        prop = panel.getProperty(propertyName)

        if prop is not None:

            propertyValue = properties.getProperty(propertyName)
            propertyValue = toQProperty(propertyName, propertyValue)

            if isinstance(propertyValue, list):
                for i, subValue in enumerate(propertyValue):
                    panel.getSubProperty(prop, i).setValue(subValue)

                groupName = PropertyPanelHelper.getPropertyGroupName(propertyName, propertyValue)
                prop.setPropertyName(groupName)

            else:
                prop.setValue(propertyValue)

    @staticmethod
    def setPropertyFromPanel(prop, propertiesPanel, propertySet):

        if prop.isSubProperty():
            if not propertiesPanel.getParentProperty(prop):
                return

            propertyIndex = propertiesPanel.getSubPropertyIndex(prop)
            propertyName = prop.propertyName()
            propertyName = propertyName[:propertyName.index('[')]

            propertyValue = propertySet.getProperty(propertyName)
            propertyValue = list(propertyValue)
            propertyValue[propertyIndex] = prop.value()

            propertySet.setProperty(propertyName, propertyValue)

            groupName = PropertyPanelHelper.getPropertyGroupName(propertyName, propertyValue)
            propertiesPanel.getParentProperty(prop).setPropertyName(groupName)

        else:

            propertyName = prop.propertyName()
            propertyValue = prop.value()
            propertyValue = fromQColor(propertyName, propertyValue)
            propertySet.setProperty(propertyName, propertyValue)

    @staticmethod
    def _setPropertyAttributes(prop, attributes):

        prop.setAttribute('decimals', attributes.decimals)
        prop.setAttribute('minimum', attributes.minimum)
        prop.setAttribute('maximum', attributes.maximum)
        prop.setAttribute('singleStep', attributes.singleStep)
        if attributes.enumNames:
            prop.setAttribute('enumNames', attributes.enumNames)

    @staticmethod
    def getPropertyGroupName(name, value):
        return '%s [%s]' % (name, ', '.join(['%.2f' % v if isinstance(v, float) else str(v) for v in value]))

    @staticmethod
    def _addProperty(panel, name, attributes, value):

        value = toQProperty(name, value)

        if isinstance(value, list):
            groupName = PropertyPanelHelper.getPropertyGroupName(name, value)
            groupProp = panel.addGroup(name, groupName)
            for v in value:
                p = panel.addSubProperty(name, v, groupProp)
                PropertyPanelHelper._setPropertyAttributes(p, attributes)
            return groupProp
        elif attributes.enumNames:
            p = panel.addEnumProperty(name, value)
            PropertyPanelHelper._setPropertyAttributes(p, attributes)
            p.setValue(value)
            return p
        else:
            p = panel.addProperty(name, value)
            PropertyPanelHelper._setPropertyAttributes(p, attributes)
            return p

class PropertyPanelConnector(object):
    def __init__(self, propertySet, propertiesPanel, propertyNamesToAdd=None):
        self.propertySet = propertySet
        self.propertyNamesToAdd = propertyNamesToAdd
        self.propertiesPanel = propertiesPanel
        self.propertySet.connectPropertyAdded(self._onPropertyAdded)
        self.propertySet.connectPropertyChanged(self._onPropertyChanged)
        self.propertySet.connectPropertyAttributeChanged(self._onPropertyAttributeChanged)
        self.propertiesPanel.connect('propertyValueChanged(QtVariantProperty*)', self._onPanelPropertyChanged)

        self._blockSignals = True
        PropertyPanelHelper.addPropertiesToPanel(self.propertySet, self.propertiesPanel, self.propertyNamesToAdd)
        self._blockSignals = False

    def cleanup(self):
        self.propertiesPanel.disconnect('propertyValueChanged(QtVariantProperty*)', self._onPanelPropertyChanged)

    def _onPropertyAdded(self, propertySet, propertyName):
        self._blockSignals = True
        self.propertiesPanel.clear()
        PropertyPanelHelper.addPropertiesToPanel(propertySet, self.propertiesPanel)
        self._blockSignals = False

    def _onPropertyAttributeChanged(self, propertySet, propertyName, propertyAttribute):
        self._blockSignals = True
        self.propertiesPanel.clear()
        PropertyPanelHelper.addPropertiesToPanel(propertySet, self.propertiesPanel)
        self._blockSignals = False

    def _onPropertyChanged(self, propertySet, propertyName):
        self._blockSignals = True
        PropertyPanelHelper.onPropertyValueChanged(self.propertiesPanel, propertySet, propertyName)
        self._blockSignals = False

    def _onPanelPropertyChanged(self, panelProperty):
        if not self._blockSignals:
            PropertyPanelHelper.setPropertyFromPanel(panelProperty, self.propertiesPanel, self.propertySet)
<commit_msg>prevent crash by scheduling the property panel rebuild<commit_after>from director import callbacks
from director.fieldcontainer import FieldContainer
from director.timercallback import TimerCallback

import re
import numpy as np
from collections import OrderedDict

def cleanPropertyName(s):
    """
    Generate a valid python property name by replacing all non-alphanumeric characters with underscores and adding an initial underscore if the first character is a digit
    """
    return re.sub(r'\W|^(?=\d)','_',s).lower()  # \W matches non-alphanumeric, ^(?=\d) matches the first position if followed by a digit

class PropertyAttributes(FieldContainer):

    def __init__(self, **kwargs):

        self._add_fields(
          decimals = 5,
          minimum = -1e4,
          maximum = 1e4,
          singleStep = 1,
          hidden = False,
          enumNames = None,
          readOnly = False,
          )

        self._set_fields(**kwargs)

from PythonQt import QtGui

def fromQColor(propertyName, propertyValue):
    if isinstance(propertyValue, QtGui.QColor):
        return [propertyValue.red()/255.0, propertyValue.green()/255.0, propertyValue.blue()/255.0]
    else:
        return propertyValue

def toQProperty(propertyName, propertyValue):
    if 'color' in propertyName.lower() and isinstance(propertyValue, (list, tuple)) and len(propertyValue) == 3:
        return QtGui.QColor(propertyValue[0]*255.0, propertyValue[1]*255.0, propertyValue[2]*255.0)
    elif isinstance(propertyValue, np.float):
        return float(propertyValue)
    elif isinstance(propertyValue, (list, tuple, np.ndarray)) and len(propertyValue) and isinstance(propertyValue[0], np.float):
        return [float(x) for x in propertyValue]
    else:
        return propertyValue

class PropertySet(object):

    PROPERTY_CHANGED_SIGNAL = 'PROPERTY_CHANGED_SIGNAL'
    PROPERTY_ADDED_SIGNAL = 'PROPERTY_ADDED_SIGNAL'
    PROPERTY_ATTRIBUTE_CHANGED_SIGNAL = 'PROPERTY_ATTRIBUTE_CHANGED_SIGNAL'

    def __getstate__(self):
        d = dict(_properties=self._properties, _attributes=self._attributes)
        return d

    def __setstate__(self, state):
        self.__init__()
        attrs = state['_attributes']
        for propName, propValue in state['_properties'].iteritems():
            self.addProperty(propName, propValue, attributes=attrs.get(propName))

    def __init__(self):

        self.callbacks = callbacks.CallbackRegistry([self.PROPERTY_CHANGED_SIGNAL,
                                                     self.PROPERTY_ADDED_SIGNAL,
                                                     self.PROPERTY_ATTRIBUTE_CHANGED_SIGNAL])

        self._properties = OrderedDict()
        self._attributes = {}
        self._alternateNames = {}

    def propertyNames(self):
        return self._properties.keys()

    def hasProperty(self, propertyName):
        return propertyName in self._properties

    def assertProperty(self, propertyName):
        assert self.hasProperty(propertyName), "Missing property: {:s}".format(propertyName)

    def connectPropertyChanged(self, func):
        return self.callbacks.connect(self.PROPERTY_CHANGED_SIGNAL, func)

    def disconnectPropertyChanged(self, callbackId):
        self.callbacks.disconnect(callbackId)

    def connectPropertyAdded(self, func):
        return self.callbacks.connect(self.PROPERTY_ADDED_SIGNAL, func)

    def disconnectPropertyAdded(self, callbackId):
        self.callbacks.disconnect(callbackId)

    def connectPropertyAttributeChanged(self, func):
        return self.callbacks.connect(self.PROPERTY_ATTRIBUTE_CHANGED_SIGNAL, func)

    def disconnectPropertyAttributeChanged(self, callbackId):
        self.callbacks.disconnect(callbackId)

    def getProperty(self, propertyName):
        self.assertProperty(propertyName)
        return self._properties[propertyName]

    def getPropertyEnumValue(self, propertyName):
        self.assertProperty(propertyName)
        return self._attributes[propertyName].enumNames[self._properties[propertyName]]

    def removeProperty(self, propertyName):
        assert self.hasProperty(propertyName)
        alternateName = cleanPropertyName(propertyName)
        del self._alternateNames[alternateName]
        del self._properties[propertyName]
        del self._attributes[propertyName]

    def addProperty(self, propertyName, propertyValue, attributes=None):
        alternateName = cleanPropertyName(propertyName)
        if propertyName not in self._properties and alternateName in self._alternateNames:
            raise ValueError('Adding this property would conflict with a different existing property with alternate name {:s}'.format(alternateName))

        propertyValue = fromQColor(propertyName, propertyValue)

        self._alternateNames[alternateName] = propertyName
        self._properties[propertyName] = propertyValue
        self._attributes[propertyName] = attributes or PropertyAttributes()

        self.callbacks.process(self.PROPERTY_ADDED_SIGNAL, self, propertyName)

    def setPropertyIndex(self, propertyName, newIndex):
        assert self.hasProperty(propertyName)
        currentIndex = self._properties.keys().index(propertyName)
        inds = range(len(self._properties))
        inds.remove(currentIndex)
        inds.insert(newIndex, currentIndex)
        items = self._properties.items()
        self._properties = OrderedDict([items[i] for i in inds])

    def setProperty(self, propertyName, propertyValue):
        self.assertProperty(propertyName)
        propertyValue = fromQColor(propertyName, propertyValue)

        names = self.getPropertyAttribute(propertyName, 'enumNames')
        if names and type(propertyValue) != int:
            propertyValue = names.index(propertyValue)

        self.oldPropertyValue = (propertyName, self.getProperty(propertyName))
        self._properties[propertyName] = propertyValue
        self.oldPropertyValue = None
        self.callbacks.process(self.PROPERTY_CHANGED_SIGNAL, self, propertyName)

    def getPropertyAttribute(self, propertyName, propertyAttribute):
        self.assertProperty(propertyName)
        return getattr(self._attributes[propertyName], propertyAttribute)

    def setPropertyAttribute(self, propertyName, propertyAttribute, value):
        self.assertProperty(propertyName)
        attributes = self._attributes[propertyName]
        assert hasattr(attributes, propertyAttribute), "Missing attribute: {:s}".format(propertyAttribute)
        setattr(attributes, propertyAttribute, value)
        self.callbacks.process(self.PROPERTY_ATTRIBUTE_CHANGED_SIGNAL, self, propertyName, propertyAttribute)

    def __getattribute__(self, name):
        try:
            alternateNames = object.__getattribute__(self, '_alternateNames')
            if name in alternateNames:
                return object.__getattribute__(self, 'getProperty')(alternateNames[name])
            else:
                raise AttributeError()
        except AttributeError:
            return object.__getattribute__(self, name)

class PropertyPanelHelper(object):

    @staticmethod
    def addPropertiesToPanel(properties, panel, propertyNamesToAdd = None):

        for propertyName in properties.propertyNames():
            value = properties.getProperty(propertyName)
            attributes = properties._attributes[propertyName]

            if value is not None and not attributes.hidden:
                addThisProperty = True
                if (propertyNamesToAdd is not None):
                    if (propertyName not in propertyNamesToAdd):
                        addThisProperty = False

                if addThisProperty:
                    PropertyPanelHelper._addProperty(panel, propertyName, attributes, value)

    @staticmethod
    def onPropertyValueChanged(panel, properties, propertyName):
        prop = panel.getProperty(propertyName)

        if prop is not None:

            propertyValue = properties.getProperty(propertyName)
            propertyValue = toQProperty(propertyName, propertyValue)

            if isinstance(propertyValue, list):
                for i, subValue in enumerate(propertyValue):
                    panel.getSubProperty(prop, i).setValue(subValue)

                groupName = PropertyPanelHelper.getPropertyGroupName(propertyName, propertyValue)
                prop.setPropertyName(groupName)

            else:
                prop.setValue(propertyValue)

    @staticmethod
    def setPropertyFromPanel(prop, propertiesPanel, propertySet):

        if prop.isSubProperty():
            if not propertiesPanel.getParentProperty(prop):
                return

            propertyIndex = propertiesPanel.getSubPropertyIndex(prop)
            propertyName = prop.propertyName()
            propertyName = propertyName[:propertyName.index('[')]

            propertyValue = propertySet.getProperty(propertyName)
            propertyValue = list(propertyValue)
            propertyValue[propertyIndex] = prop.value()

            propertySet.setProperty(propertyName, propertyValue)

            groupName = PropertyPanelHelper.getPropertyGroupName(propertyName, propertyValue)
            propertiesPanel.getParentProperty(prop).setPropertyName(groupName)

        else:

            propertyName = prop.propertyName()
            propertyValue = prop.value()
            propertyValue = fromQColor(propertyName, propertyValue)
            propertySet.setProperty(propertyName, propertyValue)

    @staticmethod
    def _setPropertyAttributes(prop, attributes):

        prop.setAttribute('decimals', attributes.decimals)
        prop.setAttribute('minimum', attributes.minimum)
        prop.setAttribute('maximum', attributes.maximum)
        prop.setAttribute('singleStep', attributes.singleStep)
        if attributes.enumNames:
            prop.setAttribute('enumNames', attributes.enumNames)

    @staticmethod
    def getPropertyGroupName(name, value):
        return '%s [%s]' % (name, ', '.join(['%.2f' % v if isinstance(v, float) else str(v) for v in value]))

    @staticmethod
    def _addProperty(panel, name, attributes, value):

        value = toQProperty(name, value)

        if isinstance(value, list):
            groupName = PropertyPanelHelper.getPropertyGroupName(name, value)
            groupProp = panel.addGroup(name, groupName)
            for v in value:
                p = panel.addSubProperty(name, v, groupProp)
                PropertyPanelHelper._setPropertyAttributes(p, attributes)
            return groupProp
        elif attributes.enumNames:
            p = panel.addEnumProperty(name, value)
            PropertyPanelHelper._setPropertyAttributes(p, attributes)
            p.setValue(value)
            return p
        else:
            p = panel.addProperty(name, value)
            PropertyPanelHelper._setPropertyAttributes(p, attributes)
            return p

class PropertyPanelConnector(object):
    def __init__(self, propertySet, propertiesPanel, propertyNamesToAdd=None):
        self.propertySet = propertySet
        self.propertyNamesToAdd = propertyNamesToAdd
        self.propertiesPanel = propertiesPanel
        self.propertySet.connectPropertyAdded(self._onPropertyAdded)
        self.propertySet.connectPropertyChanged(self._onPropertyChanged)
        self.propertySet.connectPropertyAttributeChanged(self._onPropertyAttributeChanged)
        self.propertiesPanel.connect('propertyValueChanged(QtVariantProperty*)', self._onPanelPropertyChanged)

        self.timer = TimerCallback()
        self.timer.callback = self._rebuildNow

        self._blockSignals = True
        PropertyPanelHelper.addPropertiesToPanel(self.propertySet, self.propertiesPanel, self.propertyNamesToAdd)
        self._blockSignals = False

    def cleanup(self):
        self.propertiesPanel.disconnect('propertyValueChanged(QtVariantProperty*)', self._onPanelPropertyChanged)

    def _rebuild(self):
        if not self.timer.singleShotTimer.isActive():
            self.timer.singleShot(0)

    def _rebuildNow(self):
        self._blockSignals = True
        self.propertiesPanel.clear()
        PropertyPanelHelper.addPropertiesToPanel(self.propertySet, self.propertiesPanel)
        self._blockSignals = False

    def _onPropertyAdded(self, propertySet, propertyName):
        self._rebuild()

    def _onPropertyAttributeChanged(self, propertySet, propertyName, propertyAttribute):
        self._rebuild()

    def _onPropertyChanged(self, propertySet, propertyName):
        self._blockSignals = True
        PropertyPanelHelper.onPropertyValueChanged(self.propertiesPanel, propertySet, propertyName)
        self._blockSignals = False

    def _onPanelPropertyChanged(self, panelProperty):
        if not self._blockSignals:
            PropertyPanelHelper.setPropertyFromPanel(panelProperty, self.propertiesPanel, self.propertySet)
<|endoftext|>


<commit_before>from __future__ import print_function
import numpy as np
import networkx as nx
import random
import gzip
import time
import argparse
from gensim.models import Word2Vec

class node2vec(object):

	def __init__(self, is_directed, preprocessing, is_weighted, p, q, walk_length, num_walks, dimensions, window_size, workers, iterations):

		#graph properties
		self.is_directed = is_directed
		self.preprocessing = preprocessing
		self.is_weighted = is_weighted

		#walk properties
		self.p = p
		self.q = q
		self.walk_length = walk_length
		self.num_walks = num_walks

		#learning properties
		self.dimensions = dimensions
		self.window_size = window_size
		self.workers = workers
		self.iter = iterations

	def read_graph(self, nx_G):

		if self.is_weighted:

			self.G = nx.read_edgelist(nx_G,  data=(('weight',float),), create_using=nx.DiGraph(), edgetype = str)

		else:

			self.G = nx.read_edgelist(nx_G, create_using=nx.DiGraph(), edgetype = str)

			for edge in self.G.edges():
				self.G[edge[0]][edge[1]]['weight'] = 1

		if not self.is_directed:

			self.G = self.G.to_undirected()

	def node2vec_walk(self, start_node):
		'''
		Simulate a random walk starting from start node.
		'''
		G = self.G

		walk = [start_node]

		while len(walk) < self.walk_length:

			cur = walk[-1]
			cur_nbrs = sorted(G.neighbors(cur))

			if len(cur_nbrs) > 0:

				if self.preprocessing:

					alias_nodes = self.alias_nodes
					alias_edges = self.alias_edges

					if len(walk) == 1: #first step of the walk, no previous node

						walk.append(cur_nbrs[node2vec.alias_draw(alias_nodes[cur][0], alias_nodes[cur][1])])

					else:
						prev = walk[-2]

						next_node = cur_nbrs[node2vec.alias_draw(alias_edges[(prev, cur)][0],
							alias_edges[(prev, cur)][1])]

						walk.append(next_node)

				else:

					p = self.p
					q = self.q
					G = self.G

					unnormalized_probs = []

					if len(walk) == 1: #first step of the walk, no previous node

						for dst_nbr in cur_nbrs:

							unnormalized_probs.append(G[cur][dst_nbr]['weight'])

						norm_const = sum(unnormalized_probs)

						normalized_probs =  [float(u_prob)/norm_const for u_prob in unnormalized_probs]

						next_node = cur_nbrs[np.random.multinomial(1,normalized_probs).argmax()]

						walk.append(next_node)

					else:

						prev = walk[-2]

						for dst_nbr in cur_nbrs:

							if dst_nbr == prev:

								unnormalized_probs.append(G[cur][dst_nbr]['weight']/p)

							elif G.has_edge(dst_nbr, prev):
								unnormalized_probs.append(G[cur][dst_nbr]['weight'])
							else:
								unnormalized_probs.append(G[cur][dst_nbr]['weight']/q)

						norm_const = sum(unnormalized_probs)
						normalized_probs =  [float(u_prob)/norm_const for u_prob in unnormalized_probs]

						next_node = cur_nbrs[np.random.multinomial(1,normalized_probs).argmax()]

						walk.append(next_node)
			else:
				break

		return walk

	def learn_embeddings(self, output):
		'''
		Learn embeddings by optimizing the Skipgram objective using SGD.
		'''

		model = Word2Vec(self, size=self.dimensions, window=self.window_size, min_count=0,
			workers=self.workers, iter=self.iter, negative = 25, sg = 1)

		print("defined model using w2v")

		model.wv.save_word2vec_format(output, binary = True)

		print("saved model in word2vec format")

		return

	def get_alias_edge(self, src, dst):
		'''
		Get the alias edge setup lists for a given edge.
		'''
		G = self.G
		p = self.p
		q = self.q

		unnormalized_probs = []
		for dst_nbr in sorted(G.neighbors(dst)):
			if dst_nbr == src:
				unnormalized_probs.append(G[dst][dst_nbr]['weight']/p)
			elif G.has_edge(dst_nbr, src):
				unnormalized_probs.append(G[dst][dst_nbr]['weight'])
			else:
				unnormalized_probs.append(G[dst][dst_nbr]['weight']/q)
		norm_const = sum(unnormalized_probs)
		normalized_probs =  [float(u_prob)/norm_const for u_prob in unnormalized_probs]

		return node2vec.alias_setup(normalized_probs)

	def __iter__(self):

		'''
		Generator of walks simulate random walks from each node.
		'''
		G = self.G
		nodes = G.nodes()
		print('Walk iteration:')

		for walk_iter in range(self.num_walks):

			print(str(walk_iter+1), '/', str(self.num_walks))
			random.shuffle(nodes)

			c = 1

			for node in nodes:

				if c%10001 == 0:
					print('Processed %d nodes'%c)

				c += 1

				yield self.node2vec_walk(start_node=node)

	def preprocess_transition_probs(self):
		'''
		Preprocessing of transition probabilities for guiding the random walks.
		'''
		G = self.G
		is_directed = self.is_directed

		alias_nodes = {}
		for node in G.nodes():
			unnormalized_probs = [G[node][nbr]['weight'] for nbr in sorted(G.neighbors(node))]
			norm_const = sum(unnormalized_probs)
			normalized_probs =  [float(u_prob)/norm_const for u_prob in unnormalized_probs]
			alias_nodes[node] = node2vec.alias_setup(normalized_probs)

		alias_edges = {}
		triads = {}

		if is_directed:
			for edge in G.edges():
				alias_edges[edge] = self.get_alias_edge(edge[0], edge[1])
		else:
			for edge in G.edges():
				alias_edges[edge] = self.get_alias_edge(edge[0], edge[1])
				alias_edges[(edge[1], edge[0])] = self.get_alias_edge(edge[1], edge[0])

		self.alias_nodes = alias_nodes
		self.alias_edges = alias_edges

		return

	@staticmethod
	def alias_setup(probs):
		'''
		Compute utility lists for non-uniform sampling from discrete distributions.
		Refer to https://hips.seas.harvard.edu/blog/2013/03/03/the-alias-method-efficient-sampling-with-many-discrete-outcomes/
		for details
		'''
		K = len(probs)
		q = np.zeros(K)
		J = np.zeros(K, dtype=np.int)

		smaller = []
		larger = []
		for kk, prob in enumerate(probs):
		    q[kk] = K*prob
		    if q[kk] < 1.0:
		        smaller.append(kk)
		    else:
		        larger.append(kk)

		while len(smaller) > 0 and len(larger) > 0:
		    small = smaller.pop()
		    large = larger.pop()

		    J[small] = large
		    q[large] = q[large] + q[small] - 1.0
		    if q[large] < 1.0:
		        smaller.append(large)
		    else:
		        larger.append(large)

		return J, q

	@staticmethod
	def alias_draw(J, q):
		'''
		Draw sample from a non-uniform discrete distribution using alias sampling.
		'''
		K = len(J)

		kk = int(np.floor(np.random.rand()*K))
		if np.random.rand() < q[kk]:
		    return kk
		else:
		    return J[kk]

	@staticmethod
	def parse_args():
		'''
		Parses the node2vec arguments.
		'''
		parser = argparse.ArgumentParser(description="Run node2vec.")

		parser.add_argument('--input', nargs='?', default='graph/karate.edgelist',
		                    help='Input graph path')

		parser.add_argument('--output', nargs='?', default='walks.txt.gz',
	                   help='emb file name')

		parser.add_argument('--walk_length', type=int, default=10,
		                    help='Length of walk per source. Default is 10.')

		parser.add_argument('--num_walks', type=int, default=500,
		                    help='Number of walks per source. Default is 40.')

		parser.add_argument('--p', type=float, default=1,
		                    help='Return hyperparameter. Default is 1.')

		parser.add_argument('--q', type=float, default=1,
		                    help='Inout hyperparameter. Default is 1.')

		parser.add_argument('--weighted', dest='weighted', action='store_true',
		                    help='Boolean specifying (un)weighted. Default is unweighted.')
		parser.add_argument('--unweighted', dest='unweighted', action='store_false')
		parser.set_defaults(weighted=False)

		parser.add_argument('--directed', dest='directed', action='store_true',
		                    help='Graph is (un)directed. Default is directed.')
		parser.set_defaults(directed=False)

		parser.add_argument('--no_preprocessing', dest = 'preprocessing', action='store_false',
		                    help='Whether preprocess all transition probabilities or compute on the fly')
		parser.set_defaults(preprocessing=True)

		parser.add_argument('--dimensions', type=int, default=500,
		                    help='Number of dimensions. Default is 128.')

		parser.add_argument('--window-size', type=int, default=5,
	                    	help='Context size for optimization. Default is 10.')

		parser.add_argument('--iter', default=5, type=int,
	                      help='Number of epochs in SGD')

		parser.add_argument('--workers', type=int, default=8,
		                    help='Number of parallel workers. Default is 8.')

		return parser.parse_args()

	def run(self, input_graph, output):

		self.read_graph(input_graph)

		print('read G')

		if self.preprocessing:
			self.preprocess_transition_probs()
			print('preprocessed')

		self.learn_embeddings(output)

if __name__ == '__main__':

	start_time = time.time()

	args = node2vec.parse_args()

	print('Parameters:\n')

	print('input = %s\n' %args.input)

	print('output = %s\n' %args.output)

	print('walk length = %d\n' %args.walk_length)

	print('number of walks per entity = %d\n' %args.num_walks)

	print('p = %s\n' %args.p)

	print('q = %s\n' %args.q)

	print('weighted = %s\n' %args.weighted)

	print('directed = %s\n' %args.directed)

	print('preprocessing = %s\n' %args.preprocessing)

	print('dimensions = %s\n' %args.dimensions)

	print('iterations = %s\n' %args.iter)

	print('window size = %s\n' %args.window_size)

	print('workers = %s\n' %args.workers)

	node2vec_graph = node2vec(args.directed, args.preprocessing, args.weighted, args.p, args.q, args.walk_length, args.num_walks, args.dimensions, args.window_size, args.workers, args.iter)

	node2vec_graph.run(args.input, args.output)

	print("--- %s seconds ---" % (time.time() - start_time))
<commit_msg>switch from walks iterator to list<commit_after>from __future__ import print_function
import numpy as np
import networkx as nx
import random
import gzip
import time
import argparse
from gensim.models import Word2Vec

class node2vec(object):

	def __init__(self, is_directed, preprocessing, is_weighted, p, q, walk_length, num_walks, dimensions, window_size, workers, iterations):

		#graph properties
		self.is_directed = is_directed
		self.preprocessing = preprocessing
		self.is_weighted = is_weighted

		#walk properties
		self.p = p
		self.q = q
		self.walk_length = walk_length
		self.num_walks = num_walks

		#learning properties
		self.dimensions = dimensions
		self.window_size = window_size
		self.workers = workers
		self.iter = iterations

	def read_graph(self, nx_G):

		if self.is_weighted:

			self.G = nx.read_edgelist(nx_G,  data=(('weight',float),), create_using=nx.DiGraph(), edgetype = str)

		else:

			self.G = nx.read_edgelist(nx_G, create_using=nx.DiGraph(), edgetype = str)

			for edge in self.G.edges():
				self.G[edge[0]][edge[1]]['weight'] = 1

		if not self.is_directed:

			self.G = self.G.to_undirected()

	def node2vec_walk(self, start_node):
		'''
		Simulate a random walk starting from start node.
		'''
		G = self.G

		walk = [start_node]

		while len(walk) < self.walk_length:

			cur = walk[-1]
			cur_nbrs = sorted(G.neighbors(cur))

			if len(cur_nbrs) > 0:

				if self.preprocessing:

					alias_nodes = self.alias_nodes
					alias_edges = self.alias_edges

					if len(walk) == 1: #first step of the walk, no previous node

						walk.append(cur_nbrs[node2vec.alias_draw(alias_nodes[cur][0], alias_nodes[cur][1])])

					else:
						prev = walk[-2]

						next_node = cur_nbrs[node2vec.alias_draw(alias_edges[(prev, cur)][0],
							alias_edges[(prev, cur)][1])]

						walk.append(next_node)

				else:

					p = self.p
					q = self.q
					G = self.G

					unnormalized_probs = []

					if len(walk) == 1: #first step of the walk, no previous node

						for dst_nbr in cur_nbrs:

							unnormalized_probs.append(G[cur][dst_nbr]['weight'])

						norm_const = sum(unnormalized_probs)

						normalized_probs =  [float(u_prob)/norm_const for u_prob in unnormalized_probs]

						next_node = cur_nbrs[np.random.multinomial(1,normalized_probs).argmax()]

						walk.append(next_node)

					else:

						prev = walk[-2]

						for dst_nbr in cur_nbrs:

							if dst_nbr == prev:

								unnormalized_probs.append(G[cur][dst_nbr]['weight']/p)

							elif G.has_edge(dst_nbr, prev):
								unnormalized_probs.append(G[cur][dst_nbr]['weight'])
							else:
								unnormalized_probs.append(G[cur][dst_nbr]['weight']/q)

						norm_const = sum(unnormalized_probs)
						normalized_probs =  [float(u_prob)/norm_const for u_prob in unnormalized_probs]

						next_node = cur_nbrs[np.random.multinomial(1,normalized_probs).argmax()]

						walk.append(next_node)
			else:
				break

		return walk

	def learn_embeddings(self, output):
		'''
		Learn embeddings by optimizing the Skipgram objective using SGD.
		'''
		self._simulate_walks()

		model = Word2Vec(self._walks, size=self.dimensions, window=self.window_size, min_count=0,
			workers=self.workers, iter=self.iter, negative = 25, sg = 1)

		print("defined model using w2v")

		model.wv.save_word2vec_format(output, binary = True)
		#model.save(output)
		print("saved model in word2vec binary format")

		return

	def get_alias_edge(self, src, dst):
		'''
		Get the alias edge setup lists for a given edge.
		'''
		G = self.G
		p = self.p
		q = self.q

		unnormalized_probs = []
		for dst_nbr in sorted(G.neighbors(dst)):
			if dst_nbr == src:
				unnormalized_probs.append(G[dst][dst_nbr]['weight']/p)
			elif G.has_edge(dst_nbr, src):
				unnormalized_probs.append(G[dst][dst_nbr]['weight'])
			else:
				unnormalized_probs.append(G[dst][dst_nbr]['weight']/q)
		norm_const = sum(unnormalized_probs)
		normalized_probs =  [float(u_prob)/norm_const for u_prob in unnormalized_probs]

		return node2vec.alias_setup(normalized_probs)

	def _simulate_walks(self):

		'''
		Generator of walks simulate random walks from each node.
		'''
		G = self.G
		nodes = G.nodes()

		self._walks = []

		print('Walk iteration:')

		for walk_iter in range(self.num_walks):

			print(str(walk_iter+1), '/', str(self.num_walks))
			random.shuffle(nodes)

			c = 1

			for node in nodes:

				if c%10001 == 0:
					print('Processed %d nodes'%c)

				c += 1

				self._walks.append(self.node2vec_walk(start_node=node))

	def preprocess_transition_probs(self):
		'''
		Preprocessing of transition probabilities for guiding the random walks.
		'''
		G = self.G
		is_directed = self.is_directed

		alias_nodes = {}
		for node in G.nodes():
			unnormalized_probs = [G[node][nbr]['weight'] for nbr in sorted(G.neighbors(node))]
			norm_const = sum(unnormalized_probs)
			normalized_probs =  [float(u_prob)/norm_const for u_prob in unnormalized_probs]
			alias_nodes[node] = node2vec.alias_setup(normalized_probs)

		alias_edges = {}
		triads = {}

		if is_directed:
			for edge in G.edges():
				alias_edges[edge] = self.get_alias_edge(edge[0], edge[1])
		else:
			for edge in G.edges():
				alias_edges[edge] = self.get_alias_edge(edge[0], edge[1])
				alias_edges[(edge[1], edge[0])] = self.get_alias_edge(edge[1], edge[0])

		self.alias_nodes = alias_nodes
		self.alias_edges = alias_edges

		return

	@staticmethod
	def alias_setup(probs):
		'''
		Compute utility lists for non-uniform sampling from discrete distributions.
		Refer to https://hips.seas.harvard.edu/blog/2013/03/03/the-alias-method-efficient-sampling-with-many-discrete-outcomes/
		for details
		'''
		K = len(probs)
		q = np.zeros(K)
		J = np.zeros(K, dtype=np.int)

		smaller = []
		larger = []
		for kk, prob in enumerate(probs):
		    q[kk] = K*prob
		    if q[kk] < 1.0:
		        smaller.append(kk)
		    else:
		        larger.append(kk)

		while len(smaller) > 0 and len(larger) > 0:
		    small = smaller.pop()
		    large = larger.pop()

		    J[small] = large
		    q[large] = q[large] + q[small] - 1.0
		    if q[large] < 1.0:
		        smaller.append(large)
		    else:
		        larger.append(large)

		return J, q

	@staticmethod
	def alias_draw(J, q):
		'''
		Draw sample from a non-uniform discrete distribution using alias sampling.
		'''
		K = len(J)

		kk = int(np.floor(np.random.rand()*K))
		if np.random.rand() < q[kk]:
		    return kk
		else:
		    return J[kk]

	@staticmethod
	def parse_args():
		'''
		Parses the node2vec arguments.
		'''
		parser = argparse.ArgumentParser(description="Run node2vec.")

		parser.add_argument('--input', nargs='?', default='graph/karate.edgelist',
		                    help='Input graph path')

		parser.add_argument('--output', nargs='?', default='walks.txt.gz',
	                   help='emb file name')

		parser.add_argument('--walk_length', type=int, default=10,
		                    help='Length of walk per source. Default is 10.')

		parser.add_argument('--num_walks', type=int, default=500,
		                    help='Number of walks per source. Default is 40.')

		parser.add_argument('--p', type=float, default=1,
		                    help='Return hyperparameter. Default is 1.')

		parser.add_argument('--q', type=float, default=1,
		                    help='Inout hyperparameter. Default is 1.')

		parser.add_argument('--weighted', dest='weighted', action='store_true',
		                    help='Boolean specifying (un)weighted. Default is unweighted.')
		parser.set_defaults(weighted=False)

		parser.add_argument('--directed', dest='directed', action='store_true',
		                    help='Graph is (un)directed. Default is directed.')
		parser.set_defaults(directed=False)

		parser.add_argument('--no_preprocessing', dest = 'preprocessing', action='store_false',
		                    help='Whether preprocess all transition probabilities or compute on the fly')
		parser.set_defaults(preprocessing=True)

		parser.add_argument('--dimensions', type=int, default=500,
		                    help='Number of dimensions. Default is 128.')

		parser.add_argument('--window-size', type=int, default=5,
	                    	help='Context size for optimization. Default is 10.')

		parser.add_argument('--iter', default=5, type=int,
	                      help='Number of epochs in SGD')

		parser.add_argument('--workers', type=int, default=8,
		                    help='Number of parallel workers. Default is 8.')

		return parser.parse_args()

	def run(self, input_graph, output):

		self.read_graph(input_graph)

		print('read G')

		if self.preprocessing:
			self.preprocess_transition_probs()
			print('preprocessed')

		self.learn_embeddings(output)

if __name__ == '__main__':

	start_time = time.time()

	args = node2vec.parse_args()

	print('Parameters:\n')

	print('input = %s\n' %args.input)

	print('output = %s\n' %args.output)

	print('walk length = %d\n' %args.walk_length)

	print('number of walks per entity = %d\n' %args.num_walks)

	print('p = %s\n' %args.p)

	print('q = %s\n' %args.q)

	print('weighted = %s\n' %args.weighted)

	print('directed = %s\n' %args.directed)

	print('preprocessing = %s\n' %args.preprocessing)

	print('dimensions = %s\n' %args.dimensions)

	print('iterations = %s\n' %args.iter)

	print('window size = %s\n' %args.window_size)

	print('workers = %s\n' %args.workers)

	node2vec_graph = node2vec(args.directed, args.preprocessing, args.weighted, args.p, args.q, args.walk_length, args.num_walks, args.dimensions, args.window_size, args.workers, args.iter)

	node2vec_graph.run(args.input, args.output)

	print("--- %s seconds ---" % (time.time() - start_time))
<|endoftext|>


<commit_before>'''Utility functions.
Created on Sep 13, 2010

@author: jnaous
'''
import os
from django.conf import settings
from geni.util.urn_util import URN
from geni.util.cert_util import create_cert
from sfa.trust.certificate import Keypair
from sfa.trust.gid import GID

def get_user_cert_fname(user):
    """Get the filename of the user's GCF x509 certificate.

    @param user: The user whose certificate filename we want.
    @type user: L{django.contrib.auth.models.User}

    @return: The certificate absolute path
    @rtype: C{str}
    """

    return os.path.join(
        settings.GCF_X509_CERT_DIR,
        settings.GCF_X509_USER_CERT_FNAME_PREFIX + user.username + ".crt"
    )

def get_user_key_fname(user):
    """Get the filename of the user's GCF x509 certificate key.

    @param user: The user whose certificate key filename we want.
    @type user: L{django.contrib.auth.models.User}

    @return: The certificate key's absolute path
    @rtype: C{str}
    """

    return os.path.join(
        settings.GCF_X509_KEY_DIR,
        settings.GCF_X509_USER_CERT_FNAME_PREFIX + user.username + ".key"
    )

def get_user_urn(user):
    """Get a user's URN

    @param user: The user whose URN we want.
    @type user: L{django.contrib.auth.models.User}

    @return: The URN
    @rtype: C{str}
    """

    return URN(
        str(settings.GCF_BASE_NAME), str("user"), str(user.username)
    ).urn_string()

def get_ch_urn():
    """Get the URN for Expedient as a clearinghouse.

    @return: The URN
    @rtype: C{str}
    """

    return URN(
        settings.GCF_BASE_NAME, "authority", "sa",
    ).urn_string()

def create_x509_cert(urn, cert_fname, key_fname, is_self_signed=False):
    """Create a GCF certificate and store it in a file.

    @param urn: The urn to use in the cert.
    @param cert_fname: The filename to store the cert in.
    @param key_fname: The filename to store the certificate key in.
    @param is_self_signed: should the certificate be self-signed? Otherwise
        it will be signed by Expedient's CH certificate. Default False.
    """
    if is_self_signed:
        cert, keys = create_cert(
            urn,
        )
    else:
        cert, keys = create_cert(
            urn,
            issuer_key=settings.GCF_X509_CH_KEY,
            issuer_cert=settings.GCF_X509_CH_CERT
        )

    cert.save_to_file(cert_fname)
    keys.save_to_file(key_fname)

def read_cert_from_file(cert_fname):
    """Read a GCF certificate from a file.

    Read the certificate from a file and put it into a C{sfa.trust.gid.GID}
    object. The returned certificate is already decoded.

    @param cert_fname: The filename to read the cert from
    @type cert_fname: C{str}
    @return: The certificate stored in the file at C{cert_fname}
    @rtype: C{sfa.trust.gid.GID}
    """

    cert = GID(filename=cert_fname)
    cert.decode()
    return cert
<commit_msg>large number of various fixes and additions<commit_after>'''Utility functions.
Created on Sep 13, 2010

@author: jnaous
'''
import os
import re
from django.conf import settings
from geni.util.urn_util import URN
from geni.util.cert_util import create_cert
from sfa.trust.gid import GID
from django.core.urlresolvers import reverse
from geni.util import cred_util

def get_user_cert_fname(user):
    """Get the filename of the user's GCF x509 certificate.

    @param user: The user whose certificate filename we want.
    @type user: L{django.contrib.auth.models.User}

    @return: The certificate absolute path
    @rtype: C{str}
    """

    return os.path.join(
        settings.GCF_X509_USER_CERT_DIR,
        settings.GCF_X509_USER_CERT_FNAME_PREFIX + user.username + ".crt"
    )

def get_user_key_fname(user):
    """Get the filename of the user's GCF x509 certificate key.

    @param user: The user whose certificate key filename we want.
    @type user: L{django.contrib.auth.models.User}

    @return: The certificate key's absolute path
    @rtype: C{str}
    """

    return os.path.join(
        settings.GCF_X509_KEY_DIR,
        settings.GCF_X509_USER_CERT_FNAME_PREFIX + user.username + ".key"
    )

def get_user_urn(username):
    """Get a user's URN

    @param username: The username of the user whose URN we want.
    @type username: C{str}

    @return: The URN
    @rtype: C{str}
    """

    return URN(
        str(settings.GCF_BASE_NAME), str("user"), str(username)
    ).urn_string()

def get_ch_urn():
    """Get the URN for Expedient as a clearinghouse.

    @return: The URN
    @rtype: C{str}
    """

    return URN(
        settings.GCF_BASE_NAME, "authority", "sa",
    ).urn_string()

def get_slice_urn(name):
    """Get the URN for a slice with name C{name}.

    @param name: Name of the slice. Must be unique.
    @type name: C{str}
    @return: a slice URN
    @rtype: C{str}

    """
    return URN(
        settings.GCF_BASE_NAME, "slice", name,
    ).urn_string()

def create_x509_cert(urn, cert_fname=None, key_fname=None, is_self_signed=False):
    """Create a GCF certificate and store it in a file.

    @param urn: The urn to use in the cert.
    @type urn: C{str}
    @keyword cert_fname: The filename to store the cert in.
        If None (default), then don't store.
    @type cert_fname: C{str}
    @keyword key_fname: The filename to store the certificate key in.
        If None (default), then don't store.
    @type key_fname: C{str}
    @keyword is_self_signed: should the certificate be self-signed? Otherwise
        it will be signed by Expedient's CH certificate. Default False.
    @type is_self_signed: C{bool}
    @return: tuple (cert, keys)
    @rtype: (C{sfa.trust.gid.GID}, C{sfa.trust.certificate.Keypair})

    """
    if is_self_signed:
        cert, keys = create_cert(
            urn,
        )
    else:
        cert, keys = create_cert(
            urn,
            issuer_key=settings.GCF_X509_CH_KEY,
            issuer_cert=settings.GCF_X509_CH_CERT
        )

    if cert_fname: cert.save_to_file(cert_fname)
    if key_fname: keys.save_to_file(key_fname)

    return cert, keys

def read_cert_from_file(cert_fname):
    """Read a GCF certificate from a file.

    Read the certificate from a file and put it into a C{sfa.trust.gid.GID}
    object. The returned certificate is already decoded.

    @param cert_fname: The filename to read the cert from
    @type cert_fname: C{str}
    @return: The certificate stored in the file at C{cert_fname}
    @rtype: C{sfa.trust.gid.GID}
    """

    cert = GID(filename=cert_fname)
    cert.decode()
    return cert

def describe_ui_plugin(slice):
    """Describes the UI plugin according to L{expedient.clearinghouse.defaultsettings.expedient.UI_PLUGINS}."""
    return ("GCF RSpec Plugin",
            "Allows the user to modify the slice by uploading"
            " RSpecs or to download an RSpec of the slice.",
            reverse("gcf_rspec_ui", slice.id))

def urn_to_username(urn):
    """Create a valid username from a URN.

    This creates the username by taking the authority part of
    the URN, and the name part of the URN and joining them with "@".

    Any characters other than letters, digits, '@', '-', '_', '+', and '.'
    are replace with '_'.

    e.g. "urn:publicid:IDN+stanford:expedient%26+user+jnaous" becomes
    "jnaous@expedient_26.stanford"

    The authority part of the URN is truncated to 155 characters, and the
    name part is truncated to 100 characters.

    @param urn: a urn to turn into a username
    @type urn: C{str}
    @return: a valid username
    @rtype: C{str}
    """

    invalid_chars_re = re.compile(r"[^\w@+.-]")

    urn = URN(urn=str(urn))
    auth = urn.getAuthority()
    auth = auth.split(":")
    auth.reverse()
    auth = ".".join(auth)
    if len(auth) > 150:
        auth = auth[:150]

    name = urn.getName()
    if len(name) > 100:
        name =name[:100]

    username = name + "@" + auth

    # replace all invalid chars with _
    username = invalid_chars_re.sub("_", username)

    assert(len(username) <= 30)

    return username

def get_trusted_cert_filenames():
    """Return list of paths to files containing trusted certs."""

    filenames = os.listdir(settings.GCF_X509_TRUSTED_CERT_DIR)
    filenames = [os.path.join(settings.GCF_X509_TRUSTED_CERT_DIR, f) \
                 for f in filenames]
    trusted_certs = []
    for f in filenames:
        if f.endswith(".crt") and os.path.isfile(f):
            trusted_certs.append(f)

def create_slice_credential(user_gid, slice_gid):
    '''Create a Slice credential object for this user_gid (object) on given slice gid (object)

    @param user_gid: The user's cert
    @type user_gid: C{sfa.trust.gid.GID}
    @param slice_gid: The slice's gid
    @type slice_gid: C{sfa.trust.gid.GID}
    '''

    return cred_util.create_credential(
        user_gid, slice_gid, settings.GCF_SLICE_CRED_LIFE,
        'slice',
        settings.GCF_X509_CH_KEY, settings.GCF_X509_CH_CERT,
        get_trusted_cert_filenames(),
    )

def create_user_credential(user_gid):
    '''Create a user credential object for this user_gid

    @param user_gid: The user's cert
    @type user_gid: C{sfa.trust.gid.GID}
    @param slice_gid: The slice's gid
    @type slice_gid: C{sfa.trust.gid.GID}
    '''

    return cred_util.create_credential(
        user_gid, user_gid, settings.GCF_USER_CRED_LIFE,
        'user',
        settings.GCF_X509_CH_KEY, settings.GCF_X509_CH_CERT,
        get_trusted_cert_filenames(),
    )
<|endoftext|>