<commit_before>##########################################################################
#
#  Copyright (c) 2012, John Haddon. All rights reserved.
#  Copyright (c) 2013, Image Engine Design Inc. All rights reserved.
#
#  Redistribution and use in source and binary forms, with or without
#  modification, are permitted provided that the following conditions are
#  met:
#
#      * Redistributions of source code must retain the above
#        copyright notice, this list of conditions and the following
#        disclaimer.
#
#      * Redistributions in binary form must reproduce the above
#        copyright notice, this list of conditions and the following
#        disclaimer in the documentation and/or other materials provided with
#        the distribution.
#
#      * Neither the name of John Haddon nor the names of
#        any other contributors to this software may be used to endorse or
#        promote products derived from this software without specific prior
#        written permission.
#
#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
#  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
#  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
#  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
#  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
#  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
#  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
#  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
#  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
#  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
#  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
##########################################################################

import functools

import imath

import IECore
import Gaffer
import GafferUI

Gaffer.Metadata.registerNode(

	Gaffer.Expression,

	"description",
	"""
	Utility node for computing values via
	scripted expressions.
	""",

	"layout:customWidget:Expression:widgetType", "GafferUI.ExpressionUI.ExpressionWidget",
	"nodeGadget:type", "GafferUI::AuxiliaryNodeGadget",
	"auxiliaryNodeGadget:label", "e",

	plugs = {

		# This plug is added by the expressionCompatibility.py
		# config file to provide compatibility for loading old
		# files, so we must hide it.
		"engine" : (

			"plugValueWidget:type", "",
			"nodule:type", "",

		),

		# This plug is added by the expressionCompatibility.py
		# config file to provide compatibility for loading old
		# files, so we must hide it.
		"expression" : (

			"plugValueWidget:type", "",
			"nodule:type", "",

		),

		"user" : (

			"plugValueWidget:type", "",

		),

	}

)

# PlugValueWidget popup menu for creating expressions
##########################################################################

def __createExpression( plug, language ) :

	node = plug.node()
	parentNode = node.ancestor( Gaffer.Node )

	with Gaffer.UndoScope( node.scriptNode() ) :

		expressionNode = Gaffer.Expression()
		parentNode.addChild( expressionNode )

		expressionNode.setExpression(
			Gaffer.Expression.defaultExpression( plug, language ),
			language
		)

	__editExpression( plug )

def __editExpression( plug ) :

	expressionNode = plug.getInput().node()

	GafferUI.NodeEditor.acquire( expressionNode )

def __popupMenu( menuDefinition, plugValueWidget ) :

	plug = plugValueWidget.getPlug()
	if not isinstance( plug, Gaffer.ValuePlug ) :
		return

	node = plug.node()
	if node is None or node.parent() is None :
		return

	input = plug.getInput()
	if input is not None or not plugValueWidget._editable() or Gaffer.MetadataAlgo.readOnly( plug ) :
		return

	languages = [ l for l in Gaffer.Expression.languages() if Gaffer.Expression.defaultExpression( plug, l ) ]
	if not languages :
		return

	menuDefinition.prepend( "/ExpressionDivider", { "divider" : True } )
	for language in languages :
		menuDefinition.prepend(
			"/Create " + IECore.CamelCase.toSpaced( language ) + " Expression...",
			{
				"command" : functools.partial( __createExpression, plug, language )
			}
		)

__popupMenuConnection = GafferUI.PlugValueWidget.popupMenuSignal().connect( __popupMenu )

# ExpressionWidget
##########################################################################

class ExpressionWidget( GafferUI.Widget ) :

	def __init__( self, node, **kw ) :

		column = GafferUI.ListContainer( spacing = 4 )
		GafferUI.Widget.__init__( self, column, **kw )

		self.__node = node

		with column :

			with GafferUI.ListContainer( GafferUI.ListContainer.Orientation.Horizontal, spacing = 4 ) :

				GafferUI.Label( "Language" )
				self.__languageMenu = GafferUI.MenuButton( "", menu = GafferUI.Menu( Gaffer.WeakMethod( self.__languageMenuDefinition ) ) )
				self.__languageMenu.setEnabled( not Gaffer.MetadataAlgo.readOnly( node ) )

			self.__textWidget = GafferUI.MultiLineTextWidget( role = GafferUI.MultiLineTextWidget.Role.Code )
			self.__textWidget.setEditable( not Gaffer.MetadataAlgo.readOnly( node ) )

			self.__activatedConnection = self.__textWidget.activatedSignal().connect( Gaffer.WeakMethod( self.__activated ) )
			self.__editingFinishedConnection = self.__textWidget.editingFinishedSignal().connect( Gaffer.WeakMethod( self.__editingFinished ) )
			self.__dropTextConnection = self.__textWidget.dropTextSignal().connect( Gaffer.WeakMethod( self.__dropText ) )
			self.__contextMenuConnection = self.__textWidget.contextMenuSignal().connect( Gaffer.WeakMethod( self.__expressionContextMenu ) )

			self.__messageWidget = GafferUI.MessageWidget()

		self.__expressionChangedConnection = self.__node.expressionChangedSignal().connect( Gaffer.WeakMethod( self.__expressionChanged ) )
		self.__errorConnection = self.__node.errorSignal().connect( Gaffer.WeakMethod( self.__error ) )

		self.__update()

	def node( self ) :

		return self.__node

	def textWidget( self ) :

		return self.__textWidget

	__expressionContextMenuSignal = Gaffer.Signal2()
	## This signal is emitted whenever a popup menu
	# for an ExpressionWidget is about to be shown.
	# This provides an opportunity to customise the
	# menu from external code. The signature for
	# slots is ( menuDefinition, widget ), and slots
	# should just modify the menu definition in place.
	@classmethod
	def expressionContextMenuSignal( cls ) :

		return cls.__expressionContextMenuSignal

	def __expressionContextMenuDefinition( self ) :

		menuDefinition = IECore.MenuDefinition()

		bookmarks = Gaffer.MetadataAlgo.bookmarks( self.__node.parent() )

		def __bookmarkMenu( bookmarks ) :

			bookmarkMenuDefinition = IECore.MenuDefinition()

			def __walk( graphComponent, result ) :

				if (
					isinstance( graphComponent, Gaffer.ValuePlug ) and
					self.__node.identifier( graphComponent ) and
					not graphComponent.relativeName( graphComponent.node() ).startswith( "__" )
				) :
					result.append( graphComponent )

				for c in graphComponent.children( Gaffer.Plug ) :
					__walk( c, result )

			for bookmark in bookmarks :

				compatiblePlugs = []
				__walk( bookmark, compatiblePlugs )

				if not compatiblePlugs :
					continue

				for plug in compatiblePlugs :
					label = "/" + bookmark.getName()
					if len( compatiblePlugs ) > 1 :
						label += "/"  + plug.relativeName( bookmark )
					bookmarkMenuDefinition.append(
						label,
						{
							"command" : functools.partial( self.__textWidget.insertText, self.__node.identifier( plug ) ),
							"active" : self.__textWidget.getEditable() and not Gaffer.MetadataAlgo.readOnly( self.__node['__expression'] ),
						}
					)

			return bookmarkMenuDefinition

		menuDefinition.append( "/Insert Bookmark", { "subMenu" : functools.partial( __bookmarkMenu, bookmarks ) } )

		self.expressionContextMenuSignal()( menuDefinition, self )

		return menuDefinition

	def __expressionContextMenu( self, *unused ) :

		menuDefinition = self.__expressionContextMenuDefinition()
		if not len( menuDefinition.items() ) :
			return False

		title = self.__node.relativeName( self.__node.scriptNode() )
		title = ".".join( [ IECore.CamelCase.join( IECore.CamelCase.split( x ) ) for x in title.split( "." ) ] )

		self.____expressionContextMenu = GafferUI.Menu( menuDefinition, title = title )
		self.____expressionContextMenu.popup()

		return True

	def __update( self ) :

		expression, language = self.__node.getExpression()

		self.__textWidget.setText( expression )
		self.__textWidget.setEnabled( bool( language ) )
		self.__languageMenu.setText( IECore.CamelCase.toSpaced( language ) if language else "Choose..." )

		self.__messageWidget.clear()
		self.__messageWidget.setVisible( False )

	def __languageMenuDefinition( self ) :

		currentLanguage = self.__node.getExpression()[1]

		result = IECore.MenuDefinition()
		for language in self.__node.languages() :
			result.append(
				"/" + IECore.CamelCase.toSpaced( language ),
				{
					"command" : functools.partial( Gaffer.WeakMethod( self.__changeLanguage ), language = language ),
					"checkBox" : language == currentLanguage,
				}
			)

		return result

	def __changeLanguage( self, unused, language ) :

		## \todo Can we do better? Maybe start with the default expression
		# for the current output plugs?
		self.__node.setExpression( "", language )

	def __setExpression( self ) :

		language = self.__node.getExpression()[1]
		with Gaffer.UndoScope( self.__node.scriptNode() ) :
			try :
				self.__node.setExpression( self.__textWidget.getText(), language )
				self.__messageWidget.setVisible( False )
			except Exception as e :
				self.__messageWidget.clear()
				self.__messageWidget.setVisible( True )
				self.__messageWidget.messageHandler().handle(
					IECore.Msg.Level.Error, "Parse error", str( e )
				)

	def __expressionChanged( self, node ) :

		self.__update()

	def __activated( self, widget ) :

		self.__setExpression()

	def __editingFinished( self, widget ) :

		self.__setExpression()

	def __dropText( self, widget, dragData ) :

		if isinstance( dragData, IECore.StringVectorData ) :
			return repr( list( dragData ) )
		elif isinstance( dragData, Gaffer.Plug ) :
			name = self.__node.identifier( dragData )
			return name if name else None
		elif isinstance( dragData, Gaffer.Set ) :
			if len( dragData ) == 1 :
				return self.__dropText( widget, dragData[0] )
			else :
				return None

		return None

	# An error in the expression could occur during a compute triggered by a repaint.
	# ( For example, if a user uses an expression to drive Backdrop text )
	# If we forced a repaint right away, this would be a recursive repaint which could cause
	# a Qt crash, so we wait for idle.
	@GafferUI.LazyMethod()
	def __error( self, plug, source, error ) :

		self.__messageWidget.setVisible( True )
		self.__messageWidget.messageHandler().handle( IECore.Msg.Level.Error, "Execution error", error )
<commit_msg>ExpressionUI : Fix threading bug in error display<commit_after>##########################################################################
#
#  Copyright (c) 2012, John Haddon. All rights reserved.
#  Copyright (c) 2013, Image Engine Design Inc. All rights reserved.
#
#  Redistribution and use in source and binary forms, with or without
#  modification, are permitted provided that the following conditions are
#  met:
#
#      * Redistributions of source code must retain the above
#        copyright notice, this list of conditions and the following
#        disclaimer.
#
#      * Redistributions in binary form must reproduce the above
#        copyright notice, this list of conditions and the following
#        disclaimer in the documentation and/or other materials provided with
#        the distribution.
#
#      * Neither the name of John Haddon nor the names of
#        any other contributors to this software may be used to endorse or
#        promote products derived from this software without specific prior
#        written permission.
#
#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
#  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
#  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
#  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
#  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
#  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
#  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
#  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
#  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
#  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
#  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
##########################################################################

import functools

import imath

import IECore
import Gaffer
import GafferUI

Gaffer.Metadata.registerNode(

	Gaffer.Expression,

	"description",
	"""
	Utility node for computing values via
	scripted expressions.
	""",

	"layout:customWidget:Expression:widgetType", "GafferUI.ExpressionUI.ExpressionWidget",
	"nodeGadget:type", "GafferUI::AuxiliaryNodeGadget",
	"auxiliaryNodeGadget:label", "e",

	plugs = {

		# This plug is added by the expressionCompatibility.py
		# config file to provide compatibility for loading old
		# files, so we must hide it.
		"engine" : (

			"plugValueWidget:type", "",
			"nodule:type", "",

		),

		# This plug is added by the expressionCompatibility.py
		# config file to provide compatibility for loading old
		# files, so we must hide it.
		"expression" : (

			"plugValueWidget:type", "",
			"nodule:type", "",

		),

		"user" : (

			"plugValueWidget:type", "",

		),

	}

)

# PlugValueWidget popup menu for creating expressions
##########################################################################

def __createExpression( plug, language ) :

	node = plug.node()
	parentNode = node.ancestor( Gaffer.Node )

	with Gaffer.UndoScope( node.scriptNode() ) :

		expressionNode = Gaffer.Expression()
		parentNode.addChild( expressionNode )

		expressionNode.setExpression(
			Gaffer.Expression.defaultExpression( plug, language ),
			language
		)

	__editExpression( plug )

def __editExpression( plug ) :

	expressionNode = plug.getInput().node()

	GafferUI.NodeEditor.acquire( expressionNode )

def __popupMenu( menuDefinition, plugValueWidget ) :

	plug = plugValueWidget.getPlug()
	if not isinstance( plug, Gaffer.ValuePlug ) :
		return

	node = plug.node()
	if node is None or node.parent() is None :
		return

	input = plug.getInput()
	if input is not None or not plugValueWidget._editable() or Gaffer.MetadataAlgo.readOnly( plug ) :
		return

	languages = [ l for l in Gaffer.Expression.languages() if Gaffer.Expression.defaultExpression( plug, l ) ]
	if not languages :
		return

	menuDefinition.prepend( "/ExpressionDivider", { "divider" : True } )
	for language in languages :
		menuDefinition.prepend(
			"/Create " + IECore.CamelCase.toSpaced( language ) + " Expression...",
			{
				"command" : functools.partial( __createExpression, plug, language )
			}
		)

__popupMenuConnection = GafferUI.PlugValueWidget.popupMenuSignal().connect( __popupMenu )

# ExpressionWidget
##########################################################################

class ExpressionWidget( GafferUI.Widget ) :

	def __init__( self, node, **kw ) :

		column = GafferUI.ListContainer( spacing = 4 )
		GafferUI.Widget.__init__( self, column, **kw )

		self.__node = node

		with column :

			with GafferUI.ListContainer( GafferUI.ListContainer.Orientation.Horizontal, spacing = 4 ) :

				GafferUI.Label( "Language" )
				self.__languageMenu = GafferUI.MenuButton( "", menu = GafferUI.Menu( Gaffer.WeakMethod( self.__languageMenuDefinition ) ) )
				self.__languageMenu.setEnabled( not Gaffer.MetadataAlgo.readOnly( node ) )

			self.__textWidget = GafferUI.MultiLineTextWidget( role = GafferUI.MultiLineTextWidget.Role.Code )
			self.__textWidget.setEditable( not Gaffer.MetadataAlgo.readOnly( node ) )

			self.__activatedConnection = self.__textWidget.activatedSignal().connect( Gaffer.WeakMethod( self.__activated ) )
			self.__editingFinishedConnection = self.__textWidget.editingFinishedSignal().connect( Gaffer.WeakMethod( self.__editingFinished ) )
			self.__dropTextConnection = self.__textWidget.dropTextSignal().connect( Gaffer.WeakMethod( self.__dropText ) )
			self.__contextMenuConnection = self.__textWidget.contextMenuSignal().connect( Gaffer.WeakMethod( self.__expressionContextMenu ) )

			self.__messageWidget = GafferUI.MessageWidget()

		self.__expressionChangedConnection = self.__node.expressionChangedSignal().connect( Gaffer.WeakMethod( self.__expressionChanged ) )
		self.__errorConnection = self.__node.errorSignal().connect( Gaffer.WeakMethod( self.__error ) )

		self.__update()

	def node( self ) :

		return self.__node

	def textWidget( self ) :

		return self.__textWidget

	__expressionContextMenuSignal = Gaffer.Signal2()
	## This signal is emitted whenever a popup menu
	# for an ExpressionWidget is about to be shown.
	# This provides an opportunity to customise the
	# menu from external code. The signature for
	# slots is ( menuDefinition, widget ), and slots
	# should just modify the menu definition in place.
	@classmethod
	def expressionContextMenuSignal( cls ) :

		return cls.__expressionContextMenuSignal

	def __expressionContextMenuDefinition( self ) :

		menuDefinition = IECore.MenuDefinition()

		bookmarks = Gaffer.MetadataAlgo.bookmarks( self.__node.parent() )

		def __bookmarkMenu( bookmarks ) :

			bookmarkMenuDefinition = IECore.MenuDefinition()

			def __walk( graphComponent, result ) :

				if (
					isinstance( graphComponent, Gaffer.ValuePlug ) and
					self.__node.identifier( graphComponent ) and
					not graphComponent.relativeName( graphComponent.node() ).startswith( "__" )
				) :
					result.append( graphComponent )

				for c in graphComponent.children( Gaffer.Plug ) :
					__walk( c, result )

			for bookmark in bookmarks :

				compatiblePlugs = []
				__walk( bookmark, compatiblePlugs )

				if not compatiblePlugs :
					continue

				for plug in compatiblePlugs :
					label = "/" + bookmark.getName()
					if len( compatiblePlugs ) > 1 :
						label += "/"  + plug.relativeName( bookmark )
					bookmarkMenuDefinition.append(
						label,
						{
							"command" : functools.partial( self.__textWidget.insertText, self.__node.identifier( plug ) ),
							"active" : self.__textWidget.getEditable() and not Gaffer.MetadataAlgo.readOnly( self.__node['__expression'] ),
						}
					)

			return bookmarkMenuDefinition

		menuDefinition.append( "/Insert Bookmark", { "subMenu" : functools.partial( __bookmarkMenu, bookmarks ) } )

		self.expressionContextMenuSignal()( menuDefinition, self )

		return menuDefinition

	def __expressionContextMenu( self, *unused ) :

		menuDefinition = self.__expressionContextMenuDefinition()
		if not len( menuDefinition.items() ) :
			return False

		title = self.__node.relativeName( self.__node.scriptNode() )
		title = ".".join( [ IECore.CamelCase.join( IECore.CamelCase.split( x ) ) for x in title.split( "." ) ] )

		self.____expressionContextMenu = GafferUI.Menu( menuDefinition, title = title )
		self.____expressionContextMenu.popup()

		return True

	def __update( self ) :

		expression, language = self.__node.getExpression()

		self.__textWidget.setText( expression )
		self.__textWidget.setEnabled( bool( language ) )
		self.__languageMenu.setText( IECore.CamelCase.toSpaced( language ) if language else "Choose..." )

		self.__messageWidget.clear()
		self.__messageWidget.setVisible( False )

	def __languageMenuDefinition( self ) :

		currentLanguage = self.__node.getExpression()[1]

		result = IECore.MenuDefinition()
		for language in self.__node.languages() :
			result.append(
				"/" + IECore.CamelCase.toSpaced( language ),
				{
					"command" : functools.partial( Gaffer.WeakMethod( self.__changeLanguage ), language = language ),
					"checkBox" : language == currentLanguage,
				}
			)

		return result

	def __changeLanguage( self, unused, language ) :

		## \todo Can we do better? Maybe start with the default expression
		# for the current output plugs?
		self.__node.setExpression( "", language )

	def __setExpression( self ) :

		language = self.__node.getExpression()[1]
		with Gaffer.UndoScope( self.__node.scriptNode() ) :
			try :
				self.__node.setExpression( self.__textWidget.getText(), language )
				self.__messageWidget.setVisible( False )
			except Exception as e :
				self.__messageWidget.clear()
				self.__messageWidget.setVisible( True )
				self.__messageWidget.messageHandler().handle(
					IECore.Msg.Level.Error, "Parse error", str( e )
				)

	def __expressionChanged( self, node ) :

		self.__update()

	def __activated( self, widget ) :

		self.__setExpression()

	def __editingFinished( self, widget ) :

		self.__setExpression()

	def __dropText( self, widget, dragData ) :

		if isinstance( dragData, IECore.StringVectorData ) :
			return repr( list( dragData ) )
		elif isinstance( dragData, Gaffer.Plug ) :
			name = self.__node.identifier( dragData )
			return name if name else None
		elif isinstance( dragData, Gaffer.Set ) :
			if len( dragData ) == 1 :
				return self.__dropText( widget, dragData[0] )
			else :
				return None

		return None

	def __error( self, plug, source, error ) :

		# Error signal can be emitted on any thread, but we need to be on the UI
		# thread to display it.
		GafferUI.EventLoop.executeOnUIThread( functools.partial( self.__displayError, error ) )

	# An error in the expression could occur during a compute triggered by a repaint.
	# ( For example, if a user uses an expression to drive Backdrop text )
	# If we forced a repaint right away, this would be a recursive repaint which could cause
	# a Qt crash, so we wait for idle.
	@GafferUI.LazyMethod()
	def __displayError( self, error ) :

		self.__messageWidget.setVisible( True )
		self.__messageWidget.messageHandler().handle( IECore.Msg.Level.Error, "Execution error", error )
<|endoftext|>


<commit_before>##########################################################################
#
#  Copyright (c) 2012, John Haddon. All rights reserved.
#
#  Redistribution and use in source and binary forms, with or without
#  modification, are permitted provided that the following conditions are
#  met:
#
#      * Redistributions of source code must retain the above
#        copyright notice, this list of conditions and the following
#        disclaimer.
#
#      * Redistributions in binary form must reproduce the above
#        copyright notice, this list of conditions and the following
#        disclaimer in the documentation and/or other materials provided with
#        the distribution.
#
#      * Neither the name of John Haddon nor the names of
#        any other contributors to this software may be used to endorse or
#        promote products derived from this software without specific prior
#        written permission.
#
#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
#  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
#  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
#  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
#  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
#  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
#  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
#  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
#  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
#  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
#  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
##########################################################################

import Gaffer
import GafferUI

GafferUI.PlugValueWidget.registerCreator(
	Gaffer.ScriptNode.staticTypeId(),
	"frameRange",
	GafferUI.CompoundNumericPlugValueWidget
)<commit_msg>Hiding unsaved changes plug in the Settings... window.<commit_after>##########################################################################
#
#  Copyright (c) 2012, John Haddon. All rights reserved.
#  Copyright (c) 2013, Image Engine Design Inc. All rights reserved.
#
#  Redistribution and use in source and binary forms, with or without
#  modification, are permitted provided that the following conditions are
#  met:
#
#      * Redistributions of source code must retain the above
#        copyright notice, this list of conditions and the following
#        disclaimer.
#
#      * Redistributions in binary form must reproduce the above
#        copyright notice, this list of conditions and the following
#        disclaimer in the documentation and/or other materials provided with
#        the distribution.
#
#      * Neither the name of John Haddon nor the names of
#        any other contributors to this software may be used to endorse or
#        promote products derived from this software without specific prior
#        written permission.
#
#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
#  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
#  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
#  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
#  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
#  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
#  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
#  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
#  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
#  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
#  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
##########################################################################

import Gaffer
import GafferUI

GafferUI.PlugValueWidget.registerCreator(
	Gaffer.ScriptNode.staticTypeId(),
	"unsavedChanges",
	None
)

GafferUI.PlugValueWidget.registerCreator(
	Gaffer.ScriptNode.staticTypeId(),
	"frameRange",
	GafferUI.CompoundNumericPlugValueWidget
)
<|endoftext|>


<commit_before>##########################################################################
#
#  Copyright (c) 2011-2012, John Haddon. All rights reserved.
#  Copyright (c) 2011-2012, Image Engine Design Inc. All rights reserved.
#
#  Redistribution and use in source and binary forms, with or without
#  modification, are permitted provided that the following conditions are
#  met:
#
#      * Redistributions of source code must retain the above
#        copyright notice, this list of conditions and the following
#        disclaimer.
#
#      * Redistributions in binary form must reproduce the above
#        copyright notice, this list of conditions and the following
#        disclaimer in the documentation and/or other materials provided with
#        the distribution.
#
#      * Neither the name of John Haddon nor the names of
#        any other contributors to this software may be used to endorse or
#        promote products derived from this software without specific prior
#        written permission.
#
#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
#  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
#  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
#  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
#  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
#  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
#  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
#  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
#  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
#  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
#  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
##########################################################################

import weakref

import IECore

import Gaffer
import GafferUI

class ScriptWindow( GafferUI.Window ) :

	def __init__( self, script, **kw ) :

		GafferUI.Window.__init__( self, **kw )

		self.__script = script

		self.__listContainer = GafferUI.ListContainer( GafferUI.ListContainer.Orientation.Vertical, spacing = 2 )

		menuDefinition = self.menuDefinition( script.applicationRoot() ) if script.applicationRoot() else IECore.MenuDefinition()
		self.__listContainer.append( GafferUI.MenuBar( menuDefinition ) )

		applicationRoot = self.__script.ancestor( Gaffer.ApplicationRoot.staticTypeId() )
		layouts = GafferUI.Layouts.acquire( applicationRoot ) if applicationRoot is not None else None
		if layouts is not None and "Default" in layouts.names() :
			self.setLayout( layouts.create( "Default", script ) )
		else :
			self.setLayout( GafferUI.CompoundEditor( script ) )

		self.setChild( self.__listContainer )

		self.__closedConnection = self.closedSignal().connect( Gaffer.WeakMethod( self.__closed ) )

		self.__scriptPlugSetConnection = script.plugSetSignal().connect( Gaffer.WeakMethod( self.__scriptPlugChanged ) )

		self.__updateTitle()

		ScriptWindow.__instances.append( weakref.ref( self ) )

	def scriptNode( self ) :

		return self.__script

	def setLayout( self, compoundEditor ) :

		if len( self.__listContainer ) > 1 :
			del self.__listContainer[1]

		assert( compoundEditor.scriptNode().isSame( self.scriptNode() ) )
		self.__listContainer.append( compoundEditor, expand=True )

	def getLayout( self ) :

		return self.__listContainer[1]

	def _acceptsClose( self ) :

		if not self.__script["unsavedChanges"].getValue() :
			return True

		f = self.__script["fileName"].getValue()
		f = f.rpartition( "/" )[2] if f else "untitled"

		dialogue = GafferUI.ConfirmationDialogue(
			"Discard Unsaved Changes?",
			"The file %s has unsaved changes. Do you want to discard them?" % f,
			confirmLabel = "Discard"
		)
		return dialogue.waitForConfirmation()

	def __closed( self, widget ) :

		scriptParent = self.__script.parent()
		if scriptParent is not None :
			scriptParent.removeChild( self.__script )

	def __scriptPlugChanged( self, plug ) :

		if plug.isSame( self.__script["fileName"] ) or plug.isSame( self.__script["unsavedChanges"] ) :
			self.__updateTitle()

	def __updateTitle( self ) :

		f = self.__script["fileName"].getValue()
		if not f :
			f = "untitled"
			d = ""
		else :
			d, n, f = f.rpartition( "/" )
			d = " - " + d

		u = " *" if self.__script["unsavedChanges"].getValue() else ""

		self.setTitle( "Gaffer : %s%s%s" % ( f, u, d ) )

	__instances = [] # weak references to all instances - used by acquire()
	## Returns the ScriptWindow for the specified script, creating one
	# if necessary.
	@staticmethod
	def acquire( script ) :

		for w in ScriptWindow.__instances :
			scriptWindow = w()
			if scriptWindow is not None and scriptWindow.scriptNode().isSame( script ) :
				return scriptWindow

		return ScriptWindow( script )

	## Returns an IECore.MenuDefinition which is used to define the menu bars for all ScriptWindows
	# created as part of the specified application. This can be edited at any time to modify subsequently
	# created ScriptWindows - typically editing would be done as part of gaffer startup.
	@staticmethod
	def menuDefinition( applicationOrApplicationRoot ) :

		if isinstance( applicationOrApplicationRoot, Gaffer.Application ) :
			applicationRoot = applicationOrApplicationRoot.root()
		else :
			assert( isinstance( applicationOrApplicationRoot, Gaffer.ApplicationRoot ) )
			applicationRoot = applicationOrApplicationRoot

		menuDefinition = getattr( applicationRoot, "_scriptWindowMenuDefinition", None )
		if menuDefinition :
			return menuDefinition

		menuDefinition = IECore.MenuDefinition()
		applicationRoot._scriptWindowMenuDefinition = menuDefinition

		return menuDefinition

	## This function provides the top level functionality for instantiating
	# the UI. Once called, new ScriptWindows will be instantiated for each
	# script added to the application, and EventLoop.mainEventLoop().stop() will
	# be called when the last script is removed.
	__scriptAddedConnections = []
	__scriptRemovedConnections = []
	@classmethod
	def connect( cls, applicationRoot ) :

		cls.__scriptAddedConnections.append( applicationRoot["scripts"].childAddedSignal().connect( ScriptWindow.__scriptAdded ) )
		cls.__scriptRemovedConnections.append( applicationRoot["scripts"].childRemovedSignal().connect( ScriptWindow.__staticScriptRemoved ) )

	__automaticallyCreatedInstances = [] # strong references to instances made by __scriptAdded()
	@staticmethod
	def __scriptAdded( scriptContainer, script ) :

		w = ScriptWindow( script )
		w.setVisible( True )
		ScriptWindow.__automaticallyCreatedInstances.append( w )

	@staticmethod
	def __staticScriptRemoved( scriptContainer, script ) :

		for w in ScriptWindow.__automaticallyCreatedInstances :
			if w.scriptNode().isSame( script ) :
				ScriptWindow.__automaticallyCreatedInstances.remove( w )

		if not len( scriptContainer.children() ) :
			GafferUI.EventLoop.mainEventLoop().stop()
<commit_msg>Fixed positioning of ScriptWindow close confirmation dialogue.<commit_after>##########################################################################
#
#  Copyright (c) 2011-2012, John Haddon. All rights reserved.
#  Copyright (c) 2011-2012, Image Engine Design Inc. All rights reserved.
#
#  Redistribution and use in source and binary forms, with or without
#  modification, are permitted provided that the following conditions are
#  met:
#
#      * Redistributions of source code must retain the above
#        copyright notice, this list of conditions and the following
#        disclaimer.
#
#      * Redistributions in binary form must reproduce the above
#        copyright notice, this list of conditions and the following
#        disclaimer in the documentation and/or other materials provided with
#        the distribution.
#
#      * Neither the name of John Haddon nor the names of
#        any other contributors to this software may be used to endorse or
#        promote products derived from this software without specific prior
#        written permission.
#
#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
#  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
#  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
#  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
#  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
#  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
#  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
#  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
#  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
#  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
#  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
##########################################################################

import weakref

import IECore

import Gaffer
import GafferUI

class ScriptWindow( GafferUI.Window ) :

	def __init__( self, script, **kw ) :

		GafferUI.Window.__init__( self, **kw )

		self.__script = script

		self.__listContainer = GafferUI.ListContainer( GafferUI.ListContainer.Orientation.Vertical, spacing = 2 )

		menuDefinition = self.menuDefinition( script.applicationRoot() ) if script.applicationRoot() else IECore.MenuDefinition()
		self.__listContainer.append( GafferUI.MenuBar( menuDefinition ) )

		applicationRoot = self.__script.ancestor( Gaffer.ApplicationRoot.staticTypeId() )
		layouts = GafferUI.Layouts.acquire( applicationRoot ) if applicationRoot is not None else None
		if layouts is not None and "Default" in layouts.names() :
			self.setLayout( layouts.create( "Default", script ) )
		else :
			self.setLayout( GafferUI.CompoundEditor( script ) )

		self.setChild( self.__listContainer )

		self.__closedConnection = self.closedSignal().connect( Gaffer.WeakMethod( self.__closed ) )

		self.__scriptPlugSetConnection = script.plugSetSignal().connect( Gaffer.WeakMethod( self.__scriptPlugChanged ) )

		self.__updateTitle()

		ScriptWindow.__instances.append( weakref.ref( self ) )

	def scriptNode( self ) :

		return self.__script

	def setLayout( self, compoundEditor ) :

		if len( self.__listContainer ) > 1 :
			del self.__listContainer[1]

		assert( compoundEditor.scriptNode().isSame( self.scriptNode() ) )
		self.__listContainer.append( compoundEditor, expand=True )

	def getLayout( self ) :

		return self.__listContainer[1]

	def _acceptsClose( self ) :

		if not self.__script["unsavedChanges"].getValue() :
			return True

		f = self.__script["fileName"].getValue()
		f = f.rpartition( "/" )[2] if f else "untitled"

		dialogue = GafferUI.ConfirmationDialogue(
			"Discard Unsaved Changes?",
			"The file %s has unsaved changes. Do you want to discard them?" % f,
			confirmLabel = "Discard"
		)
		return dialogue.waitForConfirmation( parentWindow=self )

	def __closed( self, widget ) :

		scriptParent = self.__script.parent()
		if scriptParent is not None :
			scriptParent.removeChild( self.__script )

	def __scriptPlugChanged( self, plug ) :

		if plug.isSame( self.__script["fileName"] ) or plug.isSame( self.__script["unsavedChanges"] ) :
			self.__updateTitle()

	def __updateTitle( self ) :

		f = self.__script["fileName"].getValue()
		if not f :
			f = "untitled"
			d = ""
		else :
			d, n, f = f.rpartition( "/" )
			d = " - " + d

		u = " *" if self.__script["unsavedChanges"].getValue() else ""

		self.setTitle( "Gaffer : %s%s%s" % ( f, u, d ) )

	__instances = [] # weak references to all instances - used by acquire()
	## Returns the ScriptWindow for the specified script, creating one
	# if necessary.
	@staticmethod
	def acquire( script ) :

		for w in ScriptWindow.__instances :
			scriptWindow = w()
			if scriptWindow is not None and scriptWindow.scriptNode().isSame( script ) :
				return scriptWindow

		return ScriptWindow( script )

	## Returns an IECore.MenuDefinition which is used to define the menu bars for all ScriptWindows
	# created as part of the specified application. This can be edited at any time to modify subsequently
	# created ScriptWindows - typically editing would be done as part of gaffer startup.
	@staticmethod
	def menuDefinition( applicationOrApplicationRoot ) :

		if isinstance( applicationOrApplicationRoot, Gaffer.Application ) :
			applicationRoot = applicationOrApplicationRoot.root()
		else :
			assert( isinstance( applicationOrApplicationRoot, Gaffer.ApplicationRoot ) )
			applicationRoot = applicationOrApplicationRoot

		menuDefinition = getattr( applicationRoot, "_scriptWindowMenuDefinition", None )
		if menuDefinition :
			return menuDefinition

		menuDefinition = IECore.MenuDefinition()
		applicationRoot._scriptWindowMenuDefinition = menuDefinition

		return menuDefinition

	## This function provides the top level functionality for instantiating
	# the UI. Once called, new ScriptWindows will be instantiated for each
	# script added to the application, and EventLoop.mainEventLoop().stop() will
	# be called when the last script is removed.
	__scriptAddedConnections = []
	__scriptRemovedConnections = []
	@classmethod
	def connect( cls, applicationRoot ) :

		cls.__scriptAddedConnections.append( applicationRoot["scripts"].childAddedSignal().connect( ScriptWindow.__scriptAdded ) )
		cls.__scriptRemovedConnections.append( applicationRoot["scripts"].childRemovedSignal().connect( ScriptWindow.__staticScriptRemoved ) )

	__automaticallyCreatedInstances = [] # strong references to instances made by __scriptAdded()
	@staticmethod
	def __scriptAdded( scriptContainer, script ) :

		w = ScriptWindow( script )
		w.setVisible( True )
		ScriptWindow.__automaticallyCreatedInstances.append( w )

	@staticmethod
	def __staticScriptRemoved( scriptContainer, script ) :

		for w in ScriptWindow.__automaticallyCreatedInstances :
			if w.scriptNode().isSame( script ) :
				ScriptWindow.__automaticallyCreatedInstances.remove( w )

		if not len( scriptContainer.children() ) :
			GafferUI.EventLoop.mainEventLoop().stop()
<|endoftext|>


<commit_before>'''
  This file is part of the PyPhantomJS project.

  Copyright (C) 2011 James Roe <roejames12@hotmail.com>

  This program 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.

  This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
'''

from PyQt4.QtCore import QSettings
from PyQt4.QtNetwork import QNetworkCookie, QNetworkCookieJar

class CookieJar(QNetworkCookieJar):
    def __init__(self, parent, cookiesFile):
        super(CookieJar, self).__init__(parent)

        self.m_cookiesFile = cookiesFile

    def setCookiesFromUrl(self, cookieList, url):
        settings = QSettings(self.m_cookiesFile, QSettings.IniFormat)

        settings.beginGroup(url.host())

        for cookie in cookieList:
            settings.setValue(str(cookie.name()), str(cookie.value()))

        settings.sync()

        return True

    def cookiesForUrl(self, url):
        settings = QSettings(self.m_cookiesFile, QSettings.IniFormat)
        cookieList = []

        settings.beginGroup(url.host())

        for cname in settings.childKeys():
            cookieList.append(QNetworkCookie(cname, settings.value(cname)))

        return cookieList
<commit_msg>cookie.value() didn't really need to be a string, since QSettings will take a QVariant anyways.<commit_after>'''
  This file is part of the PyPhantomJS project.

  Copyright (C) 2011 James Roe <roejames12@hotmail.com>

  This program 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.

  This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
'''

from PyQt4.QtCore import QSettings
from PyQt4.QtNetwork import QNetworkCookie, QNetworkCookieJar

class CookieJar(QNetworkCookieJar):
    def __init__(self, parent, cookiesFile):
        super(CookieJar, self).__init__(parent)

        self.m_cookiesFile = cookiesFile

    def setCookiesFromUrl(self, cookieList, url):
        settings = QSettings(self.m_cookiesFile, QSettings.IniFormat)

        settings.beginGroup(url.host())

        for cookie in cookieList:
            settings.setValue(str(cookie.name()), cookie.value())

        settings.sync()

        return True

    def cookiesForUrl(self, url):
        settings = QSettings(self.m_cookiesFile, QSettings.IniFormat)
        cookieList = []

        settings.beginGroup(url.host())

        for cname in settings.childKeys():
            cookieList.append(QNetworkCookie(cname, settings.value(cname)))

        return cookieList
<|endoftext|>


<commit_before>## Copyright (c) 2012, 2013 Aldebaran Robotics. All rights reserved.
## Use of this source code is governed by a BSD-style license that can be
## found in the COPYING file.

"""Run the same command on each source project.
Example:
    qisrc foreach -- git reset --hard origin/mytag

Use -- to seprate qisrc arguments from the arguments of the command.
"""

import qisys.actions
import qisys.parsers
import qisrc.parsers

def configure_parser(parser):
    """Configure parser for this action """
    qisys.parsers.worktree_parser(parser)
    parser.add_argument("--git", action="store_true", dest="git_only",
        help="consider only the git projects")
    parser.add_argument("--all", action="store_false", dest="git_only",
        help="consider all the projects")
    parser.add_argument("command", metavar="COMMAND", nargs="+")
    parser.add_argument("--ignore-errors", "--continue",
        action="store_true", help="continue on error")
    parser.set_defaults(git_only=True)

def do(args):
    """Main entry point"""
    if args.git_only:
        git_worktree = qisrc.parsers.get_git_worktree(args)
        projects = git_worktree.git_projects
    else:
        worktree = qisys.parsers.get_worktree(args)
        projects = worktree.projects

    qisys.actions.foreach(projects, args.command,
                          ignore_errors=args.ignore_errors)
<commit_msg>Add short option -c for --continue in qisrc foreach<commit_after>## Copyright (c) 2012, 2013 Aldebaran Robotics. All rights reserved.
## Use of this source code is governed by a BSD-style license that can be
## found in the COPYING file.

"""Run the same command on each source project.
Example:
    qisrc foreach -- git reset --hard origin/mytag

Use -- to seprate qisrc arguments from the arguments of the command.
"""

import qisys.actions
import qisys.parsers
import qisrc.parsers

def configure_parser(parser):
    """Configure parser for this action """
    qisys.parsers.worktree_parser(parser)
    parser.add_argument("--git", action="store_true", dest="git_only",
        help="consider only the git projects")
    parser.add_argument("--all", action="store_false", dest="git_only",
        help="consider all the projects")
    parser.add_argument("command", metavar="COMMAND", nargs="+")
    parser.add_argument("-c", "--ignore-errors", "--continue",
        action="store_true", help="continue on error")
    parser.set_defaults(git_only=True)

def do(args):
    """Main entry point"""
    if args.git_only:
        git_worktree = qisrc.parsers.get_git_worktree(args)
        projects = git_worktree.git_projects
    else:
        worktree = qisys.parsers.get_worktree(args)
        projects = worktree.projects

    qisys.actions.foreach(projects, args.command,
                          ignore_errors=args.ignore_errors)
<|endoftext|>


<commit_before>from django.contrib import admin
from django import forms
from django.contrib.auth.models import User

from mezzanine.core.admin import TabularDynamicInlineAdmin, SingletonAdmin
from mezzanine.pages.admin import PageAdmin

from models import SiteConfiguration, HomePage, IconBox, UserQuota, QuotaMessage

class IconBoxInline(TabularDynamicInlineAdmin):
    model = IconBox
    extra = 5
    max_num = 5

class HomePageAdmin(PageAdmin):
    inlines = (IconBoxInline,)

class UserQuotaForm(forms.ModelForm):
    user = forms.ModelChoiceField(queryset=User.objects.all())

    class Meta:
        model = UserQuota
        fields = ['user', 'allocated_value', 'used_value', 'unit', 'zone']

    def save(self, *args, **kwargs):
        instance = super(UserQuotaForm, self).save(commit=False)
        instance.user = self.cleaned_data['user']
        return instance

class QuotaAdmin(admin.ModelAdmin):
    model = UserQuota

    list_display = ('user', 'allocated_value', 'used_value', 'unit', 'zone')
    list_filter = ('zone', 'user__username', )

    def get_form(self, request, obj=None, **kwargs):
        # use a customized form class when adding a UserQuota object so that
        # the foreign key user field is available for selection.
        if obj is None:
            return UserQuotaForm
        else:
            return super(QuotaAdmin, self).get_form(request, obj, **kwargs)

admin.site.register(HomePage, HomePageAdmin)
admin.site.register(SiteConfiguration, SingletonAdmin)
admin.site.register(UserQuota, QuotaAdmin)
admin.site.register(QuotaMessage, SingletonAdmin)
<commit_msg>some further code refinement<commit_after>from django.contrib import admin
from django import forms
from django.contrib.auth.models import User

from mezzanine.core.admin import TabularDynamicInlineAdmin, SingletonAdmin
from mezzanine.pages.admin import PageAdmin

from models import SiteConfiguration, HomePage, IconBox, UserQuota, QuotaMessage

class IconBoxInline(TabularDynamicInlineAdmin):
    model = IconBox
    extra = 5
    max_num = 5

class HomePageAdmin(PageAdmin):
    inlines = (IconBoxInline,)

class UserQuotaForm(forms.ModelForm):
    user = forms.ModelChoiceField(queryset=User.objects.exclude(is_superuser=True))

    class Meta:
        model = UserQuota
        fields = ['user', 'allocated_value', 'used_value', 'unit', 'zone']

    def save(self, *args, **kwargs):
        instance = super(UserQuotaForm, self).save(commit=False)
        instance.user = self.cleaned_data['user']
        return instance

class QuotaAdmin(admin.ModelAdmin):
    model = UserQuota

    list_display = ('user', 'allocated_value', 'used_value', 'unit', 'zone')
    list_filter = ('zone', 'user__username', )

    def get_form(self, request, obj=None, **kwargs):
        # use a customized form class when adding a UserQuota object so that
        # the foreign key user field is available for selection.
        if obj is None:
            return UserQuotaForm
        else:
            return super(QuotaAdmin, self).get_form(request, obj, **kwargs)

admin.site.register(HomePage, HomePageAdmin)
admin.site.register(SiteConfiguration, SingletonAdmin)
admin.site.register(UserQuota, QuotaAdmin)
admin.site.register(QuotaMessage, SingletonAdmin)
<|endoftext|>


<commit_before>import binascii
import collections
import datetime
import errno
import logging
import os
import shutil
import tempfile

import ray.utils

logger = logging.getLogger(__name__)
_incremental_dict = collections.defaultdict(lambda: 0)
_temp_root = None

def make_inc_temp(suffix="", prefix="", directory_name="/tmp/ray"):
    """Return a incremental temporary file name. The file is not created.

    Args:
        suffix (str): The suffix of the temp file.
        prefix (str): The prefix of the temp file.
        directory_name (str) : The base directory of the temp file.

    Returns:
        A string of file name. If there existing a file having the same name,
        the returned name will look like
        "{directory_name}/{prefix}.{unique_index}{suffix}"
    """
    directory_name = os.path.expanduser(directory_name)
    index = _incremental_dict[suffix, prefix, directory_name]
    # `tempfile.TMP_MAX` could be extremely large,
    # so using `range` in Python2.x should be avoided.
    while index < tempfile.TMP_MAX:
        if index == 0:
            filename = os.path.join(directory_name, prefix + suffix)
        else:
            filename = os.path.join(directory_name,
                                    prefix + "." + str(index) + suffix)
        index += 1
        if not os.path.exists(filename):
            _incremental_dict[suffix, prefix,
                              directory_name] = index  # Save the index.
            return filename

    raise FileExistsError(errno.EEXIST, "No usable temporary filename found")

def try_to_create_directory(directory_path):
    """Attempt to create a directory that is globally readable/writable.

    Args:
        directory_path: The path of the directory to create.
    """
    directory_path = os.path.expanduser(directory_path)
    if not os.path.exists(directory_path):
        try:
            os.makedirs(directory_path)
        except OSError as e:
            if e.errno != os.errno.EEXIST:
                raise e
            logger.warning(
                "Attempted to create '{}', but the directory already "
                "exists.".format(directory_path))
        # Change the log directory permissions so others can use it. This is
        # important when multiple people are using the same machine.
        os.chmod(directory_path, 0o0777)

def get_temp_root():
    """Get the path of the temporary root. If not existing, it will be created.
    """
    global _temp_root

    date_str = datetime.datetime.today().strftime("%Y-%m-%d_%H-%M-%S")

    # Lazy creation. Avoid creating directories never used.
    if _temp_root is None:
        _temp_root = make_inc_temp(
            prefix="session_{date_str}_{pid}".format(
                pid=os.getpid(), date_str=date_str),
            directory_name="/tmp/ray")
    try_to_create_directory(_temp_root)
    return _temp_root

def set_temp_root(path):
    """Set the path of the temporary root. It will be created lazily."""
    global _temp_root
    _temp_root = path

def get_logs_dir_path():
    """Get a temp dir for logging."""
    logs_dir = os.path.join(get_temp_root(), "logs")
    try_to_create_directory(logs_dir)
    return logs_dir

def get_sockets_dir_path():
    """Get a temp dir for sockets."""
    sockets_dir = os.path.join(get_temp_root(), "sockets")
    try_to_create_directory(sockets_dir)
    return sockets_dir

def get_raylet_socket_name(suffix=""):
    """Get a socket name for raylet."""
    sockets_dir = get_sockets_dir_path()

    raylet_socket_name = make_inc_temp(
        prefix="raylet", directory_name=sockets_dir, suffix=suffix)
    return raylet_socket_name

def get_object_store_socket_name():
    """Get a socket name for plasma object store."""
    sockets_dir = get_sockets_dir_path()
    return make_inc_temp(prefix="plasma_store", directory_name=sockets_dir)

def get_ipython_notebook_path(port):
    """Get a new ipython notebook path"""

    notebook_filepath = os.path.join(
        os.path.dirname(os.path.abspath(__file__)), "WebUI.ipynb")
    # We copy the notebook file so that the original doesn't get modified by
    # the user.
    notebook_name = make_inc_temp(
        suffix=".ipynb", prefix="ray_ui", directory_name=get_temp_root())
    shutil.copy(notebook_filepath, notebook_name)
    new_notebook_directory = os.path.dirname(notebook_name)
    token = ray.utils.decode(binascii.hexlify(os.urandom(24)))
    webui_url = ("http://localhost:{}/notebooks/{}?token={}".format(
        port, os.path.basename(notebook_name), token))
    return new_notebook_directory, webui_url, token

def new_log_files(name, redirect_output):
    """Generate partially randomized filenames for log files.

    Args:
        name (str): descriptive string for this log file.
        redirect_output (bool): True if files should be generated for logging
            stdout and stderr and false if stdout and stderr should not be
            redirected.

    Returns:
        If redirect_output is true, this will return a tuple of two
            filehandles. The first is for redirecting stdout and the second is
            for redirecting stderr. If redirect_output is false, this will
            return a tuple of two None objects.
    """
    if not redirect_output:
        return None, None

    # Create a directory to be used for process log files.
    logs_dir = get_logs_dir_path()
    # Create another directory that will be used by some of the RL algorithms.

    # TODO(suquark): This is done by the old code.
    # We should be able to control its path later.
    try_to_create_directory("/tmp/ray")

    log_stdout = make_inc_temp(
        suffix=".out", prefix=name, directory_name=logs_dir)
    log_stderr = make_inc_temp(
        suffix=".err", prefix=name, directory_name=logs_dir)
    # Line-buffer the output (mode 1)
    log_stdout_file = open(log_stdout, "a", buffering=1)
    log_stderr_file = open(log_stderr, "a", buffering=1)
    return log_stdout_file, log_stderr_file

def new_redis_log_file(redirect_output, shard_number=None):
    """Create new logging files for redis"""
    if shard_number is None:
        redis_stdout_file, redis_stderr_file = new_log_files(
            "redis", redirect_output)
    else:
        redis_stdout_file, redis_stderr_file = new_log_files(
            "redis-shard_{}".format(shard_number), redirect_output)
    return redis_stdout_file, redis_stderr_file

def new_raylet_log_file(local_scheduler_index, redirect_output):
    """Create new logging files for raylet."""
    raylet_stdout_file, raylet_stderr_file = new_log_files(
        "raylet_{}".format(local_scheduler_index),
        redirect_output=redirect_output)
    return raylet_stdout_file, raylet_stderr_file

def new_webui_log_file():
    """Create new logging files for web ui."""
    ui_stdout_file, ui_stderr_file = new_log_files(
        "webui", redirect_output=True)
    return ui_stdout_file, ui_stderr_file

def new_worker_redirected_log_file(worker_id):
    """Create new logging files for workers to redirect its output."""
    worker_stdout_file, worker_stderr_file = (new_log_files(
        "worker-" + ray.utils.binary_to_hex(worker_id), True))
    return worker_stdout_file, worker_stderr_file

def new_log_monitor_log_file():
    """Create new logging files for the log monitor."""
    log_monitor_stdout_file, log_monitor_stderr_file = new_log_files(
        "log_monitor", redirect_output=True)
    return log_monitor_stdout_file, log_monitor_stderr_file

def new_plasma_store_log_file(local_scheduler_index, redirect_output):
    """Create new logging files for the plasma store."""
    plasma_store_stdout_file, plasma_store_stderr_file = new_log_files(
        "plasma_store_{}".format(local_scheduler_index), redirect_output)
    return plasma_store_stdout_file, plasma_store_stderr_file

def new_monitor_log_file(redirect_output):
    """Create new logging files for the monitor."""
    monitor_stdout_file, monitor_stderr_file = new_log_files(
        "monitor", redirect_output)
    return monitor_stdout_file, monitor_stderr_file
<commit_msg>Allowing multiple users to access the /tmp/ray file at the same time (#3591)<commit_after>import binascii
import collections
import datetime
import errno
import logging
import os
import shutil
import tempfile

import ray.utils

logger = logging.getLogger(__name__)
_incremental_dict = collections.defaultdict(lambda: 0)
_temp_root = None

def make_inc_temp(suffix="", prefix="", directory_name="/tmp/ray"):
    """Return a incremental temporary file name. The file is not created.

    Args:
        suffix (str): The suffix of the temp file.
        prefix (str): The prefix of the temp file.
        directory_name (str) : The base directory of the temp file.

    Returns:
        A string of file name. If there existing a file having the same name,
        the returned name will look like
        "{directory_name}/{prefix}.{unique_index}{suffix}"
    """
    directory_name = os.path.expanduser(directory_name)
    index = _incremental_dict[suffix, prefix, directory_name]
    # `tempfile.TMP_MAX` could be extremely large,
    # so using `range` in Python2.x should be avoided.
    while index < tempfile.TMP_MAX:
        if index == 0:
            filename = os.path.join(directory_name, prefix + suffix)
        else:
            filename = os.path.join(directory_name,
                                    prefix + "." + str(index) + suffix)
        index += 1
        if not os.path.exists(filename):
            _incremental_dict[suffix, prefix,
                              directory_name] = index  # Save the index.
            return filename

    raise FileExistsError(errno.EEXIST, "No usable temporary filename found")

def try_to_create_directory(directory_path):
    """Attempt to create a directory that is globally readable/writable.

    Args:
        directory_path: The path of the directory to create.
    """
    directory_path = os.path.expanduser(directory_path)
    if not os.path.exists(directory_path):
        try:
            os.makedirs(directory_path)
        except OSError as e:
            if e.errno != os.errno.EEXIST:
                raise e
            logger.warning(
                "Attempted to create '{}', but the directory already "
                "exists.".format(directory_path))
        # Change the log directory permissions so others can use it. This is
        # important when multiple people are using the same machine.
    try:
        os.chmod(directory_path, 0o0777)
    except PermissionError:
        pass

def get_temp_root():
    """Get the path of the temporary root. If not existing, it will be created.
    """
    global _temp_root

    date_str = datetime.datetime.today().strftime("%Y-%m-%d_%H-%M-%S")

    # Lazy creation. Avoid creating directories never used.
    if _temp_root is None:
        _temp_root = make_inc_temp(
            prefix="session_{date_str}_{pid}".format(
                pid=os.getpid(), date_str=date_str),
            directory_name="/tmp/ray")
    try_to_create_directory(_temp_root)
    return _temp_root

def set_temp_root(path):
    """Set the path of the temporary root. It will be created lazily."""
    global _temp_root
    _temp_root = path

def get_logs_dir_path():
    """Get a temp dir for logging."""
    logs_dir = os.path.join(get_temp_root(), "logs")
    try_to_create_directory(logs_dir)
    return logs_dir

def get_sockets_dir_path():
    """Get a temp dir for sockets."""
    sockets_dir = os.path.join(get_temp_root(), "sockets")
    try_to_create_directory(sockets_dir)
    return sockets_dir

def get_raylet_socket_name(suffix=""):
    """Get a socket name for raylet."""
    sockets_dir = get_sockets_dir_path()

    raylet_socket_name = make_inc_temp(
        prefix="raylet", directory_name=sockets_dir, suffix=suffix)
    return raylet_socket_name

def get_object_store_socket_name():
    """Get a socket name for plasma object store."""
    sockets_dir = get_sockets_dir_path()
    return make_inc_temp(prefix="plasma_store", directory_name=sockets_dir)

def get_ipython_notebook_path(port):
    """Get a new ipython notebook path"""

    notebook_filepath = os.path.join(
        os.path.dirname(os.path.abspath(__file__)), "WebUI.ipynb")
    # We copy the notebook file so that the original doesn't get modified by
    # the user.
    notebook_name = make_inc_temp(
        suffix=".ipynb", prefix="ray_ui", directory_name=get_temp_root())
    shutil.copy(notebook_filepath, notebook_name)
    new_notebook_directory = os.path.dirname(notebook_name)
    token = ray.utils.decode(binascii.hexlify(os.urandom(24)))
    webui_url = ("http://localhost:{}/notebooks/{}?token={}".format(
        port, os.path.basename(notebook_name), token))
    return new_notebook_directory, webui_url, token

def new_log_files(name, redirect_output):
    """Generate partially randomized filenames for log files.

    Args:
        name (str): descriptive string for this log file.
        redirect_output (bool): True if files should be generated for logging
            stdout and stderr and false if stdout and stderr should not be
            redirected.

    Returns:
        If redirect_output is true, this will return a tuple of two
            filehandles. The first is for redirecting stdout and the second is
            for redirecting stderr. If redirect_output is false, this will
            return a tuple of two None objects.
    """
    if not redirect_output:
        return None, None

    # Create a directory to be used for process log files.
    logs_dir = get_logs_dir_path()
    # Create another directory that will be used by some of the RL algorithms.

    # TODO(suquark): This is done by the old code.
    # We should be able to control its path later.
    try_to_create_directory("/tmp/ray")

    log_stdout = make_inc_temp(
        suffix=".out", prefix=name, directory_name=logs_dir)
    log_stderr = make_inc_temp(
        suffix=".err", prefix=name, directory_name=logs_dir)
    # Line-buffer the output (mode 1)
    log_stdout_file = open(log_stdout, "a", buffering=1)
    log_stderr_file = open(log_stderr, "a", buffering=1)
    return log_stdout_file, log_stderr_file

def new_redis_log_file(redirect_output, shard_number=None):
    """Create new logging files for redis"""
    if shard_number is None:
        redis_stdout_file, redis_stderr_file = new_log_files(
            "redis", redirect_output)
    else:
        redis_stdout_file, redis_stderr_file = new_log_files(
            "redis-shard_{}".format(shard_number), redirect_output)
    return redis_stdout_file, redis_stderr_file

def new_raylet_log_file(local_scheduler_index, redirect_output):
    """Create new logging files for raylet."""
    raylet_stdout_file, raylet_stderr_file = new_log_files(
        "raylet_{}".format(local_scheduler_index),
        redirect_output=redirect_output)
    return raylet_stdout_file, raylet_stderr_file

def new_webui_log_file():
    """Create new logging files for web ui."""
    ui_stdout_file, ui_stderr_file = new_log_files(
        "webui", redirect_output=True)
    return ui_stdout_file, ui_stderr_file

def new_worker_redirected_log_file(worker_id):
    """Create new logging files for workers to redirect its output."""
    worker_stdout_file, worker_stderr_file = (new_log_files(
        "worker-" + ray.utils.binary_to_hex(worker_id), True))
    return worker_stdout_file, worker_stderr_file

def new_log_monitor_log_file():
    """Create new logging files for the log monitor."""
    log_monitor_stdout_file, log_monitor_stderr_file = new_log_files(
        "log_monitor", redirect_output=True)
    return log_monitor_stdout_file, log_monitor_stderr_file

def new_plasma_store_log_file(local_scheduler_index, redirect_output):
    """Create new logging files for the plasma store."""
    plasma_store_stdout_file, plasma_store_stderr_file = new_log_files(
        "plasma_store_{}".format(local_scheduler_index), redirect_output)
    return plasma_store_stdout_file, plasma_store_stderr_file

def new_monitor_log_file(redirect_output):
    """Create new logging files for the monitor."""
    monitor_stdout_file, monitor_stderr_file = new_log_files(
        "monitor", redirect_output)
    return monitor_stdout_file, monitor_stderr_file
<|endoftext|>


<commit_before>__version__ = "8.0.6"
__release__ = True
<commit_msg>Set version to v8.0.7 (#517)<commit_after>__version__ = "8.0.7"
__release__ = True
<|endoftext|>


<commit_before># Copyright (c) 2021 by Apex.AI Inc. 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.
#
# SPDX-License-Identifier: Apache-2.0

import os

import unittest

import launch
from launch_ros.substitutions import ExecutableInPackage
import launch_testing
import launch_testing.actions
from launch_testing.asserts import assertSequentialStdout

import pytest

# @brief Test goal: "Integrationtest for the complexdata example of iceoryx"
# @pre setup ROS2 launch executables for RouDi (debug mode) and the example processes
# @post check if all applications return exitcode 0 (success) after test run
@pytest.mark.launch_test
def generate_test_description():

    proc_env = os.environ.copy()
    colcon_prefix_path = os.environ.get('COLCON_PREFIX_PATH', '')
    executable_list = ['iox-cpp-publisher-vector', 'iox-cpp-subscriber-vector',
                       'iox-cpp-publisher-complexdata', 'iox-cpp-subscriber-complexdata']
    process_list = []

    for exec in executable_list:
        tmp_exec = os.path.join(
            colcon_prefix_path,
            'example_complexdata/bin/',
            exec)
        tmp_process = launch.actions.ExecuteProcess(
            cmd=[tmp_exec],
            env=proc_env, output='screen')
        process_list.append(tmp_process)

    print("Process list:", process_list)

    roudi_executable = os.path.join(
        colcon_prefix_path,
        'iceoryx_posh/bin/',
        'iox-roudi'
    )
    roudi_process = launch.actions.ExecuteProcess(
        cmd=[roudi_executable, '-l', 'debug'],
        env=proc_env, output='screen',
        sigterm_timeout='20')

    return launch.LaunchDescription([
        process_list[0],
        process_list[1],
        process_list[2],
        process_list[3],
        roudi_process,
        launch_testing.actions.ReadyToTest()
    ]), {'iox-cpp-publisher-vector': process_list[0], 'iox-cpp-subscriber-vector': process_list[1],
         'iox-cpp-publisher-complexdata': process_list[2], 'iox-cpp-subscriber-complexdata': process_list[3],
         'roudi_process': roudi_process}

# These tests will run concurrently with the dut process. After this test is done,
# the launch system will shut down RouDi

class TestComplexDataExample(unittest.TestCase):
    def test_roudi_ready(self, proc_output):
        proc_output.assertWaitFor(
            'RouDi is ready for clients', timeout=45, stream='stdout')

    def test_publisher_subscriber_data_exchange(self, proc_output):
        proc_output.assertWaitFor(
            'iox-cpp-subscriber-vector got values: 15, 16, 17, 18, 19', timeout=45, stream='stdout')

    def test_publisher_subscriber_untyped_data_exchange(self, proc_output):
        proc_output.assertWaitFor(
            'iox-cpp-subscriber-complexdata got values:\nstringForwardList: hello, world\nintegerList: 15, 22, 11\noptionalList: optional is empty, 42\nfloatStack: 44, 33, 22, 11, 0\nsomeString: hello iceoryx\ndoubleVector: 11, 12, 13, 14, 15\nvariantVector: seven, 8, nine',
            timeout=45, stream='stdout')

# These tests run after shutdown and examine the stdout log

@ launch_testing.post_shutdown_test()
class TestComplexdataExampleExitCodes(unittest.TestCase):
    def test_exit_code(self, proc_info):
        launch_testing.asserts.assertExitCodes(proc_info)

<commit_msg>iox-#482 remove space between @ and name<commit_after># Copyright (c) 2021 by Apex.AI Inc. 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.
#
# SPDX-License-Identifier: Apache-2.0

import os

import unittest

import launch
from launch_ros.substitutions import ExecutableInPackage
import launch_testing
import launch_testing.actions
from launch_testing.asserts import assertSequentialStdout

import pytest

# @brief Test goal: "Integrationtest for the complexdata example of iceoryx"
# @pre setup ROS2 launch executables for RouDi (debug mode) and the example processes
# @post check if all applications return exitcode 0 (success) after test run
@pytest.mark.launch_test
def generate_test_description():

    proc_env = os.environ.copy()
    colcon_prefix_path = os.environ.get('COLCON_PREFIX_PATH', '')
    executable_list = ['iox-cpp-publisher-vector', 'iox-cpp-subscriber-vector',
                       'iox-cpp-publisher-complexdata', 'iox-cpp-subscriber-complexdata']
    process_list = []

    for exec in executable_list:
        tmp_exec = os.path.join(
            colcon_prefix_path,
            'example_complexdata/bin/',
            exec)
        tmp_process = launch.actions.ExecuteProcess(
            cmd=[tmp_exec],
            env=proc_env, output='screen')
        process_list.append(tmp_process)

    print("Process list:", process_list)

    roudi_executable = os.path.join(
        colcon_prefix_path,
        'iceoryx_posh/bin/',
        'iox-roudi'
    )
    roudi_process = launch.actions.ExecuteProcess(
        cmd=[roudi_executable, '-l', 'debug'],
        env=proc_env, output='screen',
        sigterm_timeout='20')

    return launch.LaunchDescription([
        process_list[0],
        process_list[1],
        process_list[2],
        process_list[3],
        roudi_process,
        launch_testing.actions.ReadyToTest()
    ]), {'iox-cpp-publisher-vector': process_list[0], 'iox-cpp-subscriber-vector': process_list[1],
         'iox-cpp-publisher-complexdata': process_list[2], 'iox-cpp-subscriber-complexdata': process_list[3],
         'roudi_process': roudi_process}

# These tests will run concurrently with the dut process. After this test is done,
# the launch system will shut down RouDi

class TestComplexDataExample(unittest.TestCase):
    def test_roudi_ready(self, proc_output):
        proc_output.assertWaitFor(
            'RouDi is ready for clients', timeout=45, stream='stdout')

    def test_publisher_subscriber_data_exchange(self, proc_output):
        proc_output.assertWaitFor(
            'iox-cpp-subscriber-vector got values: 15, 16, 17, 18, 19', timeout=45, stream='stdout')

    def test_publisher_subscriber_untyped_data_exchange(self, proc_output):
        proc_output.assertWaitFor(
            'iox-cpp-subscriber-complexdata got values:\nstringForwardList: hello, world\nintegerList: 15, 22, 11\noptionalList: optional is empty, 42\nfloatStack: 44, 33, 22, 11, 0\nsomeString: hello iceoryx\ndoubleVector: 11, 12, 13, 14, 15\nvariantVector: seven, 8, nine',
            timeout=45, stream='stdout')

# These tests run after shutdown and examine the stdout log

@launch_testing.post_shutdown_test()
class TestComplexdataExampleExitCodes(unittest.TestCase):
    def test_exit_code(self, proc_info):
        launch_testing.asserts.assertExitCodes(proc_info)

<|endoftext|>


<commit_before># Copyright 2013 The Servo Project Developers. See the COPYRIGHT
# file at the top-level directory of this distribution.
#
# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
# option. This file may not be copied, modified, or distributed
# except according to those terms.

from __future__ import print_function, unicode_literals
from os import path, getcwd, listdir

import sys

from mach.decorators import (
    CommandArgument,
    CommandProvider,
    Command,
)

from servo.command_base import CommandBase, cd, call

@CommandProvider
class MachCommands(CommandBase):
    @Command('cargo',
             description='Run Cargo',
             category='devenv')
    @CommandArgument(
        'params', default=None, nargs='...',
        help="Command-line arguments to be passed through to Cargo")
    def cargo(self, params):
        if not params:
            params = []

        self.ensure_bootstrapped()

        if self.context.topdir == getcwd():
            with cd(path.join('components', 'servo')):
                return call(["cargo"] + params, env=self.build_env())
        return call(['cargo'] + params, env=self.build_env())

    @Command('cargo-geckolib',
             description='Run Cargo with the same compiler version and root crate as build-geckolib',
             category='devenv')
    @CommandArgument(
        'params', default=None, nargs='...',
        help="Command-line arguments to be passed through to Cargo")
    def cargo_geckolib(self, params):
        if not params:
            params = []

        self.set_use_stable_rust()
        self.ensure_bootstrapped()
        env = self.build_env(geckolib=True)

        if self.context.topdir == getcwd():
            with cd(path.join('ports', 'geckolib')):
                return call(["cargo"] + params, env=env)
        return call(['cargo'] + params, env=env)

    @Command('cargo-update',
             description='Same as update-cargo',
             category='devenv')
    @CommandArgument(
        'params', default=None, nargs='...',
        help='Command-line arguments to be passed through to cargo update')
    @CommandArgument(
        '--package', '-p', default=None,
        help='Updates selected package')
    @CommandArgument(
        '--all-packages', '-a', action='store_true',
        help='Updates all packages')
    def cargo_update(self, params=None, package=None, all_packages=None):
        self.update_cargo(params, package, all_packages)

    @Command('update-cargo',
             description='Update Cargo dependencies',
             category='devenv')
    @CommandArgument(
        'params', default=None, nargs='...',
        help='Command-line arguments to be passed through to cargo update')
    @CommandArgument(
        '--package', '-p', default=None,
        help='Updates the selected package')
    @CommandArgument(
        '--all-packages', '-a', action='store_true',
        help='Updates all packages. NOTE! This is very likely to break your ' +
             'working copy, making it impossible to build servo. Only do ' +
             'this if you really know what you are doing.')
    def update_cargo(self, params=None, package=None, all_packages=None):
        if not params:
            params = []

        if package:
            params += ["-p", package]
        elif all_packages:
            params = []
        else:
            print("Please choose package to update with the --package (-p) ")
            print("flag or update all packages with --all-packages (-a) flag")
            sys.exit(1)

        self.ensure_bootstrapped()

        with cd(self.context.topdir):
            call(["cargo", "update"] + params,
                 env=self.build_env())

    @Command('rustc',
             description='Run the Rust compiler',
             category='devenv')
    @CommandArgument(
        'params', default=None, nargs='...',
        help="Command-line arguments to be passed through to rustc")
    def rustc(self, params):
        if params is None:
            params = []

        self.ensure_bootstrapped()

        return call(["rustc"] + params, env=self.build_env())

    @Command('rustc-geckolib',
             description='Run the Rust compiler with the same compiler version and root crate as build-geckolib',
             category='devenv')
    @CommandArgument(
        'params', default=None, nargs='...',
        help="Command-line arguments to be passed through to rustc")
    def rustc_geckolib(self, params):
        if params is None:
            params = []

        self.set_use_stable_rust()
        self.ensure_bootstrapped()
        env = self.build_env(geckolib=True)

        return call(["rustc"] + params, env=env)

    @Command('rust-root',
             description='Print the path to the root of the Rust compiler',
             category='devenv')
    def rust_root(self):
        print(self.config["tools"]["rust-root"])

    @Command('grep',
             description='`git grep` for selected directories.',
             category='devenv')
    @CommandArgument(
        'params', default=None, nargs='...',
        help="Command-line arguments to be passed through to `git grep`")
    def grep(self, params):
        if not params:
            params = []
        # get all directories under tests/
        tests_dirs = listdir('tests')
        # Directories to be excluded under tests/
        excluded_tests_dirs = ['wpt', 'jquery']
        tests_dirs = filter(lambda dir: dir not in excluded_tests_dirs, tests_dirs)
        # Set of directories in project root
        root_dirs = ['components', 'ports', 'python', 'etc', 'resources']
        # Generate absolute paths for directories in tests/ and project-root/
        tests_dirs_abs = [path.join(self.context.topdir, 'tests', s) for s in tests_dirs]
        root_dirs_abs = [path.join(self.context.topdir, s) for s in root_dirs]
        # Absolute paths for all directories to be considered
        grep_paths = root_dirs_abs + tests_dirs_abs
        return call(
            ["git"] + ["grep"] + params + ['--'] + grep_paths + [':(exclude)*.min.js', ':(exclude)*.min.css'],
            env=self.build_env())

    @Command('fetch',
             description='Fetch Rust, Cargo and Cargo dependencies',
             category='devenv')
    def fetch(self):
        # Fetch Rust and Cargo
        self.ensure_bootstrapped()

        # Fetch Cargo dependencies
        with cd(self.context.topdir):
            call(["cargo", "fetch"], env=self.build_env())

    @Command('wptrunner-upgrade',
             description='upgrade wptrunner.',
             category='devenv')
    def upgrade_wpt_runner(self):
        env = self.build_env()
        with cd(path.join(self.context.topdir, 'tests', 'wpt', 'harness')):
            code = call(["git", "init"], env=env)
            if code:
                return code
            # No need to report an error if this fails, as it will for the first use
            call(["git", "remote", "rm", "upstream"], env=env)
            code = call(
                ["git", "remote", "add", "upstream", "https://github.com/w3c/wptrunner.git"], env=env)
            if code:
                return code
            code = call(["git", "fetch", "upstream"], env=env)
            if code:
                return code
            code = call(["git", "reset", "--hard", "remotes/upstream/master"], env=env)
            if code:
                return code
            code = call(["rm", "-rf", ".git"], env=env)
            if code:
                return code
            return 0
<commit_msg>Auto merge of #15857 - UK992:mach-cargo-update, r=Wafflespeanut<commit_after># Copyright 2013 The Servo Project Developers. See the COPYRIGHT
# file at the top-level directory of this distribution.
#
# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
# option. This file may not be copied, modified, or distributed
# except according to those terms.

from __future__ import print_function, unicode_literals
from os import path, getcwd, listdir

import sys

from mach.decorators import (
    CommandArgument,
    CommandProvider,
    Command,
)

from servo.command_base import CommandBase, cd, call

@CommandProvider
class MachCommands(CommandBase):
    @Command('cargo',
             description='Run Cargo',
             category='devenv')
    @CommandArgument(
        'params', default=None, nargs='...',
        help="Command-line arguments to be passed through to Cargo")
    def cargo(self, params):
        if not params:
            params = []

        self.ensure_bootstrapped()

        if self.context.topdir == getcwd():
            with cd(path.join('components', 'servo')):
                return call(["cargo"] + params, env=self.build_env())
        return call(['cargo'] + params, env=self.build_env())

    @Command('cargo-geckolib',
             description='Run Cargo with the same compiler version and root crate as build-geckolib',
             category='devenv')
    @CommandArgument(
        'params', default=None, nargs='...',
        help="Command-line arguments to be passed through to Cargo")
    def cargo_geckolib(self, params):
        if not params:
            params = []

        self.set_use_stable_rust()
        self.ensure_bootstrapped()
        env = self.build_env(geckolib=True)

        if self.context.topdir == getcwd():
            with cd(path.join('ports', 'geckolib')):
                return call(["cargo"] + params, env=env)
        return call(['cargo'] + params, env=env)

    @Command('cargo-update',
             description='Same as update-cargo',
             category='devenv')
    @CommandArgument(
        'params', default=None, nargs='...',
        help='Command-line arguments to be passed through to cargo update')
    @CommandArgument(
        '--package', '-p', default=None,
        help='Updates selected package')
    @CommandArgument(
        '--all-packages', '-a', action='store_true',
        help='Updates all packages')
    @CommandArgument(
        '--dry-run', '-d', action='store_true',
        help='Show outdated packages.')
    def cargo_update(self, params=None, package=None, all_packages=None, dry_run=None):
        self.update_cargo(params, package, all_packages, dry_run)

    @Command('update-cargo',
             description='Update Cargo dependencies',
             category='devenv')
    @CommandArgument(
        'params', default=None, nargs='...',
        help='Command-line arguments to be passed through to cargo update')
    @CommandArgument(
        '--package', '-p', default=None,
        help='Updates the selected package')
    @CommandArgument(
        '--all-packages', '-a', action='store_true',
        help='Updates all packages. NOTE! This is very likely to break your ' +
             'working copy, making it impossible to build servo. Only do ' +
             'this if you really know what you are doing.')
    @CommandArgument(
        '--dry-run', '-d', action='store_true',
        help='Show outdated packages.')
    def update_cargo(self, params=None, package=None, all_packages=None, dry_run=None):
        if not params:
            params = []

        if dry_run:
            import toml
            import json
            import httplib
            import colorama

            cargo_file = open(path.join(self.context.topdir, "Cargo.lock"))
            content = toml.load(cargo_file)

            packages = {}
            outdated_packages = 0
            conn = httplib.HTTPSConnection("crates.io")
            for package in content.get("package", []):
                if "replace" in package:
                    continue
                source = package.get("source", "")
                if source == r"registry+https://github.com/rust-lang/crates.io-index":
                    version = package["version"]
                    name = package["name"]
                    if not packages.get(name, "") or packages[name] > version:
                        packages[name] = package["version"]
                        conn.request('GET', '/api/v1/crates/{}/versions'.format(package["name"]))
                        r = conn.getresponse()
                        json_content = json.load(r)
                        for v in json_content.get("versions"):
                            if not v.get("yanked"):
                                max_version = v.get("num")
                                break

                        if version != max_version:
                            outdated_packages += 1
                            version_major, version_minor = (version.split("."))[:2]
                            max_major, max_minor = (max_version.split("."))[:2]

                            if version_major == max_major and version_minor == max_minor and "alpha" not in version:
                                msg = "minor update"
                                msg_color = "\033[93m"
                            else:
                                msg = "update, which may contain breaking changes"
                                msg_color = "\033[91m"

                            colorama.init()
                            print("{}Outdated package `{}`, available {}\033[0m".format(msg_color, name, msg),
                                  "\n\tCurrent version: {}".format(version),
                                  "\n\t Latest version: {}".format(max_version))
            conn.close()

            print("\nFound {} outdated packages from crates.io".format(outdated_packages))
        elif package:
            params += ["-p", package]
        elif all_packages:
            params = []
        else:
            print("Please choose package to update with the --package (-p) ")
            print("flag or update all packages with --all-packages (-a) flag")
            sys.exit(1)

        if params or all_packages:
            self.ensure_bootstrapped()

            with cd(self.context.topdir):
                call(["cargo", "update"] + params,
                     env=self.build_env())

    @Command('rustc',
             description='Run the Rust compiler',
             category='devenv')
    @CommandArgument(
        'params', default=None, nargs='...',
        help="Command-line arguments to be passed through to rustc")
    def rustc(self, params):
        if params is None:
            params = []

        self.ensure_bootstrapped()

        return call(["rustc"] + params, env=self.build_env())

    @Command('rustc-geckolib',
             description='Run the Rust compiler with the same compiler version and root crate as build-geckolib',
             category='devenv')
    @CommandArgument(
        'params', default=None, nargs='...',
        help="Command-line arguments to be passed through to rustc")
    def rustc_geckolib(self, params):
        if params is None:
            params = []

        self.set_use_stable_rust()
        self.ensure_bootstrapped()
        env = self.build_env(geckolib=True)

        return call(["rustc"] + params, env=env)

    @Command('rust-root',
             description='Print the path to the root of the Rust compiler',
             category='devenv')
    def rust_root(self):
        print(self.config["tools"]["rust-root"])

    @Command('grep',
             description='`git grep` for selected directories.',
             category='devenv')
    @CommandArgument(
        'params', default=None, nargs='...',
        help="Command-line arguments to be passed through to `git grep`")
    def grep(self, params):
        if not params:
            params = []
        # get all directories under tests/
        tests_dirs = listdir('tests')
        # Directories to be excluded under tests/
        excluded_tests_dirs = ['wpt', 'jquery']
        tests_dirs = filter(lambda dir: dir not in excluded_tests_dirs, tests_dirs)
        # Set of directories in project root
        root_dirs = ['components', 'ports', 'python', 'etc', 'resources']
        # Generate absolute paths for directories in tests/ and project-root/
        tests_dirs_abs = [path.join(self.context.topdir, 'tests', s) for s in tests_dirs]
        root_dirs_abs = [path.join(self.context.topdir, s) for s in root_dirs]
        # Absolute paths for all directories to be considered
        grep_paths = root_dirs_abs + tests_dirs_abs
        return call(
            ["git"] + ["grep"] + params + ['--'] + grep_paths + [':(exclude)*.min.js', ':(exclude)*.min.css'],
            env=self.build_env())

    @Command('fetch',
             description='Fetch Rust, Cargo and Cargo dependencies',
             category='devenv')
    def fetch(self):
        # Fetch Rust and Cargo
        self.ensure_bootstrapped()

        # Fetch Cargo dependencies
        with cd(self.context.topdir):
            call(["cargo", "fetch"], env=self.build_env())

    @Command('wptrunner-upgrade',
             description='upgrade wptrunner.',
             category='devenv')
    def upgrade_wpt_runner(self):
        env = self.build_env()
        with cd(path.join(self.context.topdir, 'tests', 'wpt', 'harness')):
            code = call(["git", "init"], env=env)
            if code:
                return code
            # No need to report an error if this fails, as it will for the first use
            call(["git", "remote", "rm", "upstream"], env=env)
            code = call(
                ["git", "remote", "add", "upstream", "https://github.com/w3c/wptrunner.git"], env=env)
            if code:
                return code
            code = call(["git", "fetch", "upstream"], env=env)
            if code:
                return code
            code = call(["git", "reset", "--hard", "remotes/upstream/master"], env=env)
            if code:
                return code
            code = call(["rm", "-rf", ".git"], env=env)
            if code:
                return code
            return 0
<|endoftext|>