diff --git a/frontend/blocks/mrc_call_python_function.ts b/frontend/blocks/mrc_call_python_function.ts index 2ab2067c..6c7d1571 100644 --- a/frontend/blocks/mrc_call_python_function.ts +++ b/frontend/blocks/mrc_call_python_function.ts @@ -1181,7 +1181,7 @@ export function pythonFromBlock( } case FunctionKind.EVENT: { const eventName = block.getFieldValue(FIELD_EVENT_NAME); - code = 'self.fireEvent(\'' + eventName + '\''; + code = 'self.fire_event(\'' + eventName + '\''; needOpenParen = false; delimiterBeforeArgs = ', '; break; diff --git a/frontend/blocks/mrc_class_method_def.ts b/frontend/blocks/mrc_class_method_def.ts index 94ec85bb..fa177478 100644 --- a/frontend/blocks/mrc_class_method_def.ts +++ b/frontend/blocks/mrc_class_method_def.ts @@ -376,6 +376,24 @@ const CLASS_METHOD_DEF = { }); return parameterNames; }, + upgrade_0_1_x_to_0_2_0: function(this: ClassMethodDefBlock) { + // Change opmodeStart to opmode_start + // Change opmodePeriodic to opmode_periodic + // Change opmodeEnd to opmode_end + if (!this.mrcCanChangeSignature && + !this.mrcCanBeCalledWithinClass && + !this.mrcCanBeCalledOutsideClass && + this.mrcReturnType === 'None' && + this.mrcParameters.length === 0) { + if (this.getFieldValue('NAME') === 'opmodeStart') { + this.setFieldValue('opmode_start', FIELD_METHOD_NAME); + } else if (this.getFieldValue('NAME') === 'opmodePeriodic') { + this.setFieldValue('opmode_periodic', FIELD_METHOD_NAME); + } else if (this.getFieldValue('NAME') === 'opmodeEnd') { + this.setFieldValue('opmode_end', FIELD_METHOD_NAME); + } + } + }, }; export const setup = function () { @@ -485,7 +503,7 @@ export function createCustomMethodBlock(): toolboxItems.Block { params: [], }; const fields: {[key: string]: any} = {}; - fields[FIELD_METHOD_NAME] = 'myMethod'; + fields[FIELD_METHOD_NAME] = 'my_method'; return new toolboxItems.Block(BLOCK_NAME, extraState, fields, null); } @@ -498,7 +516,7 @@ export function createCustomMethodBlockWithReturn(): toolboxItems.Block { params: [], }; const fields: {[key: string]: any} = {}; - fields[FIELD_METHOD_NAME] = 'myMethodWithReturn'; + fields[FIELD_METHOD_NAME] = 'my_method_with_return'; const inputs: {[key: string]: any} = {}; inputs[INPUT_RETURN] = { type: 'input_value', @@ -596,3 +614,12 @@ export function registerToolboxButton(workspace: Blockly.WorkspaceSvg, messageAp }); } +/** + * Upgrades the ClassMethodDefBlocks in the given workspace from version 0.1.x to 0.2.0. + * This function should only be called when upgrading old projects. + */ +export function upgrade_0_1_x_to_0_2_0(workspace: Blockly.Workspace): void { + workspace.getBlocksByType(BLOCK_NAME).forEach(block => { + (block as ClassMethodDefBlock).upgrade_0_1_x_to_0_2_0(); + }); +} diff --git a/frontend/blocks/mrc_component.ts b/frontend/blocks/mrc_component.ts index e34f9ae4..64171001 100644 --- a/frontend/blocks/mrc_component.ts +++ b/frontend/blocks/mrc_component.ts @@ -37,6 +37,7 @@ import { import { makeLegalName } from './utils/validator'; import * as toolboxItems from '../toolbox/items'; import * as storageModule from '../storage/module'; +import * as storageNames from '../storage/names'; import * as storageModuleContent from '../storage/module_content'; import { NONCOPYABLE_BLOCK } from './noncopyable_block'; import { @@ -219,7 +220,7 @@ const COMPONENT = { }, getMechanismInitArgName: function (this: ComponentBlock): string { // Return the name of the arg used to represent this component's arguments in a mechanism's - // constructor or a mechanism's defineHardware method. + // constructor or a mechanism's define_hardware method. return getMechanismInitArgName(this.getFieldValue(FIELD_NAME)); }, getComponentArgs: function (this: ComponentBlock, args: storageModuleContent.MethodArg[]): void { @@ -354,7 +355,7 @@ export const pythonFromBlock = function ( } } else { // In a mechanism, a component block does not have input sockets. - // Each argument of the mechanism's constructor (and the mechanism's defineHardware method) is + // Each argument of the mechanism's constructor (and the mechanism's define_hardware method) is // a tuple containing the constructor parameters of a component. // Use the * operator to unpack the elements of the tuple and pass each // element as a separate positional argument to the component constructor. @@ -371,7 +372,7 @@ export function getAllPossibleComponents( const contents: toolboxItems.ContentsType[] = []; // Iterate through all the component classes and add definition blocks. componentClasses.forEach(classData => { - const componentName = 'my' + simpleClassName(classData.className); + const componentName = 'my_' + storageNames.pascalCaseToSnakeCase(simpleClassName(classData.className)); classData.constructors.forEach(constructorData => { if (constructorData.isComponent) { contents.push(createComponentBlock(componentName, classData, constructorData, moduleType, showSimpleClassNames)); @@ -383,7 +384,7 @@ export function getAllPossibleComponents( } export function getMechanismInitArgName(componentName: string): string { - return componentName + 'Args'; + return componentName + '_args'; } function createComponentBlock( @@ -424,4 +425,3 @@ function createComponentBlock( }); return new toolboxItems.Block(BLOCK_NAME, extraState, fields, Object.keys(inputs).length ? inputs : null); } - diff --git a/frontend/blocks/mrc_event_handler.ts b/frontend/blocks/mrc_event_handler.ts index 8e2a720f..bd87c6d2 100644 --- a/frontend/blocks/mrc_event_handler.ts +++ b/frontend/blocks/mrc_event_handler.ts @@ -437,7 +437,7 @@ function generateRegisterEventHandler( } if (fullSender) { generator.addRegisterEventHandlerStatement( - fullSender + '.registerEventHandler(\'' + eventName + '\', self.' + funcName + ')\n'); + fullSender + '.register_event_handler(\'' + eventName + '\', self.' + funcName + ')\n'); } } diff --git a/frontend/blocks/mrc_mechanism.ts b/frontend/blocks/mrc_mechanism.ts index 2ea36a17..9ea4e8ff 100644 --- a/frontend/blocks/mrc_mechanism.ts +++ b/frontend/blocks/mrc_mechanism.ts @@ -513,11 +513,11 @@ export function createMechanismBlock( mechanism: storageModule.Mechanism, components: storageModuleContent.Component[], showSimpleClassNames: boolean): toolboxItems.Block { - const importModule = storageNames.pascalCaseToSnakeCase(mechanism.className); - const mechanismName = 'my' + mechanism.className; + const snakeCaseName = storageNames.pascalCaseToSnakeCase(mechanism.className); + const mechanismName = 'my_' + snakeCaseName; const extraState: MechanismExtraState = { mechanismModuleId: mechanism.moduleId, - importModule: importModule, + importModule: snakeCaseName, parameters: [], }; const fields: {[key: string]: any} = {}; diff --git a/frontend/blocks/mrc_mechanism_component_holder.ts b/frontend/blocks/mrc_mechanism_component_holder.ts index 815a0508..beb95cb6 100644 --- a/frontend/blocks/mrc_mechanism_component_holder.ts +++ b/frontend/blocks/mrc_mechanism_component_holder.ts @@ -332,7 +332,7 @@ export const setup = function () { } function pythonFromBlockInRobot(block: MechanismComponentHolderBlock, generator: ExtendedPythonGenerator) { - let code = 'def defineHardware(self):\n'; + let code = 'def define_hardware(self):\n'; const mechanisms = generator.statementToCode(block, INPUT_MECHANISMS); const components = generator.statementToCode(block, INPUT_COMPONENTS); @@ -344,11 +344,11 @@ function pythonFromBlockInRobot(block: MechanismComponentHolderBlock, generator: code += generator.INDENT + 'pass\n'; } - generator.addClassMethodDefinition('defineHardware', code); + generator.addClassMethodDefinition('define_hardware', code); } function pythonFromBlockInMechanism(block: MechanismComponentHolderBlock, generator: ExtendedPythonGenerator) { - let code = 'def defineHardware(self'; + let code = 'def define_hardware(self'; const mechanismInitArgNames: string[] = generator.getMechanismInitArgNames(); if (mechanismInitArgNames.length) { code += ', ' + mechanismInitArgNames.join(', '); @@ -361,7 +361,7 @@ function pythonFromBlockInMechanism(block: MechanismComponentHolderBlock, genera const allComponents = components + privateComponents; if (allComponents) { code += allComponents; - generator.addClassMethodDefinition('defineHardware', code); + generator.addClassMethodDefinition('define_hardware', code); } } @@ -419,7 +419,7 @@ export function hasAnyComponents(workspace: Blockly.Workspace): boolean { } /** - * Collects the args for the mechanism's constructor and defineHardware method. + * Collects the args for the mechanism's constructor and define_hardware method. */ export function getMechanismInitArgNames(workspace: Blockly.Workspace, mechanismInitArgNames: string[]): void { workspace.getBlocksByType(BLOCK_NAME).forEach(block => { diff --git a/frontend/blocks/utils/generated/robotpy_data.json b/frontend/blocks/utils/generated/robotpy_data.json index dec9ae73..fabe293c 100644 --- a/frontend/blocks/utils/generated/robotpy_data.json +++ b/frontend/blocks/utils/generated/robotpy_data.json @@ -24139,7 +24139,7 @@ "componentArgs": [ { "defaultValue": "", - "name": "smartIoPort", + "name": "smart_io_port", "type": "SYSTEMCORE_SMART_IO_PORT" } ], @@ -24761,7 +24761,7 @@ "componentArgs": [ { "defaultValue": "", - "name": "smartIoPort", + "name": "smart_io_port", "type": "SYSTEMCORE_SMART_IO_PORT" }, { @@ -25026,7 +25026,7 @@ "componentArgs": [ { "defaultValue": "", - "name": "smartIoPort", + "name": "smart_io_port", "type": "SYSTEMCORE_SMART_IO_PORT" }, { @@ -26638,7 +26638,7 @@ "componentArgs": [ { "defaultValue": "", - "name": "smartIoPort", + "name": "smart_io_port", "type": "SYSTEMCORE_SMART_IO_PORT" } ], @@ -28112,7 +28112,7 @@ "componentArgs": [ { "defaultValue": "", - "name": "smartIoPort", + "name": "smart_io_port", "type": "SYSTEMCORE_SMART_IO_PORT" }, { @@ -28846,7 +28846,7 @@ "componentArgs": [ { "defaultValue": "", - "name": "expansionHubMotor", + "name": "expansion_hub_motor", "type": "SYSTEMCORE_USB_PORT__EXPANSION_HUB_MOTOR_PORT" } ], @@ -29260,7 +29260,7 @@ "componentArgs": [ { "defaultValue": "", - "name": "expansionHubServo", + "name": "expansion_hub_servo", "type": "SYSTEMCORE_USB_PORT__EXPANSION_HUB_SERVO_PORT" } ], @@ -45959,7 +45959,7 @@ "componentArgs": [ { "defaultValue": "", - "name": "smartIoPort", + "name": "smart_io_port", "type": "SYSTEMCORE_SMART_IO_PORT" } ], diff --git a/frontend/blocks/utils/generated/runtime_python.json b/frontend/blocks/utils/generated/runtime_python.json index f3cabdb8..e74429c6 100644 --- a/frontend/blocks/utils/generated/runtime_python.json +++ b/frontend/blocks/utils/generated/runtime_python.json @@ -24,7 +24,7 @@ }, { "defaultValue": "", - "name": "eventName", + "name": "event_name", "type": "str" }, { @@ -34,7 +34,7 @@ } ], "declaringClassName": "blocks_base_classes.Mechanism", - "functionName": "fireEvent", + "functionName": "fire_event", "returnType": "None", "tooltip": "" }, @@ -47,7 +47,7 @@ } ], "declaringClassName": "blocks_base_classes.Mechanism", - "functionName": "opmodeEnd", + "functionName": "opmode_end", "returnType": "None", "tooltip": "" }, @@ -60,7 +60,7 @@ } ], "declaringClassName": "blocks_base_classes.Mechanism", - "functionName": "opmodePeriodic", + "functionName": "opmode_periodic", "returnType": "None", "tooltip": "" }, @@ -73,7 +73,7 @@ } ], "declaringClassName": "blocks_base_classes.Mechanism", - "functionName": "opmodeStart", + "functionName": "opmode_start", "returnType": "None", "tooltip": "" }, @@ -86,17 +86,17 @@ }, { "defaultValue": "", - "name": "eventName", + "name": "event_name", "type": "str" }, { "defaultValue": "", - "name": "eventHandler", + "name": "event_handler", "type": "typing.Callable" } ], "declaringClassName": "blocks_base_classes.Mechanism", - "functionName": "registerEventHandler", + "functionName": "register_event_handler", "returnType": "None", "tooltip": "" }, @@ -109,17 +109,17 @@ }, { "defaultValue": "", - "name": "eventName", + "name": "event_name", "type": "str" }, { "defaultValue": "", - "name": "eventHandler", + "name": "event_handler", "type": "typing.Callable" } ], "declaringClassName": "blocks_base_classes.Mechanism", - "functionName": "unregisterEventHandler", + "functionName": "unregister_event_handler", "returnType": "None", "tooltip": "" } diff --git a/frontend/blocks/utils/python.ts b/frontend/blocks/utils/python.ts index 4138534b..960a29d1 100644 --- a/frontend/blocks/utils/python.ts +++ b/frontend/blocks/utils/python.ts @@ -50,9 +50,9 @@ export const ROBOT_METHOD_NAMES_OVERRIDEABLE: string[] = [ export const CLASS_NAME_MECHANISM = MODULE_NAME_BLOCKS_BASE_CLASSES + '.Mechanism'; export const MECHANISM_METHOD_NAMES_OVERRIDEABLE: string[] = [ - 'opmodeEnd', - 'opmodePeriodic', - 'opmodeStart', + 'opmode_end', + 'opmode_periodic', + 'opmode_start', ]; export const CLASS_NAME_OPMODE = 'wpilib.PeriodicOpMode'; @@ -350,4 +350,4 @@ export function simpleClassName(className: string): string { return (lastDot !== -1) ? className.substring(lastDot + 1) : className; -} \ No newline at end of file +} diff --git a/frontend/blocks/utils/variable.ts b/frontend/blocks/utils/variable.ts index c650a7db..72420372 100644 --- a/frontend/blocks/utils/variable.ts +++ b/frontend/blocks/utils/variable.ts @@ -20,6 +20,7 @@ */ import { getAlias, simpleClassName } from './python'; +import { pascalCaseToSnakeCase } from '../../storage/names'; import * as toolboxItems from '../../toolbox/items'; @@ -62,28 +63,28 @@ export function varNameForType(type: string): string { type = alias; } - // TODO(lizlooney): Should the prefix "my" in myTuple, myDict, myCallable, myArray, and my be localized? + // TODO(lizlooney): Should the prefix "my" in my_tuple, my_dict, ... be localized? if (type.startsWith('tuple[') || type.startsWith('Tuple[')) { - return 'myTuple'; + return 'my_tuple'; } if (type.startsWith('dict[') || type.startsWith('Dict[')) { - return 'myDict'; + return 'my_dict'; } if (type.startsWith('list[') || type.startsWith('List[')) { - return 'myList'; + return 'my_list'; } if (type.startsWith('callable[') || type.startsWith('Callable[')) { - return 'myCallable'; + return 'my_callable'; } if (type.includes('[')) { // The type is an array. - return 'myArray'; + return 'my_array'; } // If the type has a dot, it is an object and we should provide a variable // block for this type. if (type.includes('.')) { - return 'my' + simpleClassName(type); + return 'my_' + pascalCaseToSnakeCase(simpleClassName(type)); } // Otherwise, we don't provide a variable block for this type. return '' diff --git a/frontend/editor/extended_python_generator.ts b/frontend/editor/extended_python_generator.ts index b9d0af8f..9e9290b2 100644 --- a/frontend/editor/extended_python_generator.ts +++ b/frontend/editor/extended_python_generator.ts @@ -134,7 +134,7 @@ export class ExtendedPythonGenerator extends PythonGenerator { private hasAnyComponents = false; private mechanismInitArgNames: string[] = []; - // Has event handlers (ie, needs to call self.registerEventHandlers in __init__) + // Has event handlers (ie, needs to call self.register_event_handlers in __init__) private hasAnyEventHandlers = false; private classMethods: {[key: string]: string} = Object.create(null); @@ -216,8 +216,8 @@ export class ExtendedPythonGenerator extends PythonGenerator { switch (this.getModuleType()) { case storageModule.ModuleType.ROBOT: initStatements += this.INDENT + 'self.mechanisms = []\n'; - initStatements += this.INDENT + 'self.eventHandlers = {}\n'; - initStatements += this.INDENT + 'self.defineHardware()\n'; + initStatements += this.INDENT + 'self.event_handlers = {}\n'; + initStatements += this.INDENT + 'self.define_hardware()\n'; for (const opModeDetails of this.allOpModeDetails) { this.fromModuleImportName('hal', 'RobotMode'); const name = opModeDetails.getName(); @@ -238,6 +238,9 @@ export class ExtendedPythonGenerator extends PythonGenerator { const opModeClassName = opModeDetails.getClassName(); const opModeModuleName = pascalCaseToSnakeCase(opModeClassName); this.importModule(opModeModuleName); + // TODO(lizlooney): When RobotPy is changed to use snake case, update the following code. + // addOpMode will likely change to add_opmode (or add_op_mode?) + // publishOpModes will likely change to publish_opmodes (or publish_op_modes?) const call = `self.addOpMode(${opModeModuleName}.${opModeClassName}, ${robotMode}, '${name}', '${group}', '${description}')`; if (opModeDetails.getEnabled()) { initStatements += this.INDENT + call + '\n'; @@ -246,13 +249,13 @@ export class ExtendedPythonGenerator extends PythonGenerator { } } initStatements += this.INDENT + 'self.publishOpModes()\n'; - //TODO: These next two lines should be removed once userControls are implemented in python. + // TODO: These next two lines should be removed once user_controls are implemented in RobotPy. this.fromModuleImportName(MODULE_NAME_BLOCKS_BASE_CLASSES, 'DefaultUserControls'); - initStatements += this.INDENT + 'self.userControls = DefaultUserControls()\n'; + initStatements += this.INDENT + 'self.user_controls = DefaultUserControls()\n'; break; case storageModule.ModuleType.MECHANISM: if (this.hasAnyComponents) { - initStatements += this.INDENT + 'self.defineHardware(' + + initStatements += this.INDENT + 'self.define_hardware(' + this.mechanismInitArgNames.join(', ') + ')\n'; } break; @@ -262,7 +265,7 @@ export class ExtendedPythonGenerator extends PythonGenerator { } if (this.hasAnyEventHandlers) { - initStatements += this.INDENT + "self.registerEventHandlers()\n"; + initStatements += this.INDENT + "self.register_event_handlers()\n"; } return initStatements; @@ -408,58 +411,58 @@ export class ExtendedPythonGenerator extends PythonGenerator { if (this.getModuleType() === storageModule.ModuleType.ROBOT) { // Define methods that we use for blocks, but are not in wpilib.OpModeRobot. this.fromModuleImportName('typing', 'Callable'); - this.classMethods['registerEventHandler'] = ( - 'def registerEventHandler(self, eventName: str, eventHandler: Callable) -> None:\n' + - this.INDENT + 'if eventName in self.eventHandlers:\n' + - this.INDENT.repeat(2) + 'self.eventHandlers[eventName].append(eventHandler)\n' + + this.classMethods['register_event_handler'] = ( + 'def register_event_handler(self, event_name: str, event_handler: Callable) -> None:\n' + + this.INDENT + 'if event_name in self.event_handlers:\n' + + this.INDENT.repeat(2) + 'self.event_handlers[event_name].append(event_handler)\n' + this.INDENT + 'else:\n' + - this.INDENT.repeat(2) + 'self.eventHandlers[eventName] = [eventHandler]\n' + this.INDENT.repeat(2) + 'self.event_handlers[event_name] = [event_handler]\n' ); - this.classMethods['unregisterEventHandler'] = ( - 'def unregisterEventHandler(self, eventName: str, eventHandler: Callable) -> None:\n' + - this.INDENT + 'if eventName in self.eventHandlers:\n' + - this.INDENT.repeat(2) + 'if eventHandler in self.eventHandlers[eventName]:\n' + - this.INDENT.repeat(3) + 'self.eventHandlers[eventName].remove(eventHandler)\n' + - this.INDENT.repeat(3) + 'if not self.eventHandlers[eventName]:\n' + - this.INDENT.repeat(4) + 'del self.eventHandlers[eventName]\n' + this.classMethods['unregister_event_handler'] = ( + 'def unregister_event_handler(self, event_name: str, event_handler: Callable) -> None:\n' + + this.INDENT + 'if event_name in self.event_handlers:\n' + + this.INDENT.repeat(2) + 'if event_handler in self.event_handlers[event_name]:\n' + + this.INDENT.repeat(3) + 'self.event_handlers[event_name].remove(event_handler)\n' + + this.INDENT.repeat(3) + 'if not self.event_handlers[event_name]:\n' + + this.INDENT.repeat(4) + 'del self.event_handlers[event_name]\n' ) - this.classMethods['fireEvent'] = ( - 'def fireEvent(self, eventName: str, *args) -> None:\n' + - this.INDENT + 'if eventName in self.eventHandlers:\n' + - this.INDENT.repeat(2) + 'for eventHandler in self.eventHandlers[eventName]:\n' + - this.INDENT.repeat(3) + 'eventHandler(*args)\n' + this.classMethods['fire_event'] = ( + 'def fire_event(self, event_name: str, *args) -> None:\n' + + this.INDENT + 'if event_name in self.event_handlers:\n' + + this.INDENT.repeat(2) + 'for event_handler in self.event_handlers[event_name]:\n' + + this.INDENT.repeat(3) + 'event_handler(*args)\n' ) - this.classMethods['opmodeStart'] = ( - 'def opmodeStart(self) -> None:\n' + + this.classMethods['opmode_start'] = ( + 'def opmode_start(self) -> None:\n' + this.INDENT + 'for mechanism in self.mechanisms:\n' + - this.INDENT.repeat(2) + 'mechanism.opmodeStart()\n' + this.INDENT.repeat(2) + 'mechanism.opmode_start()\n' ); - this.classMethods['opmodePeriodic'] = ( - 'def opmodePeriodic(self) -> None:\n' + + this.classMethods['opmode_periodic'] = ( + 'def opmode_periodic(self) -> None:\n' + this.INDENT + 'for mechanism in self.mechanisms:\n' + - this.INDENT.repeat(2) + 'mechanism.opmodePeriodic()\n' + this.INDENT.repeat(2) + 'mechanism.opmode_periodic()\n' ); - this.classMethods['opmodeEnd'] = ( - 'def opmodeEnd(self) -> None:\n' + + this.classMethods['opmode_end'] = ( + 'def opmode_end(self) -> None:\n' + this.INDENT + 'for mechanism in self.mechanisms:\n' + - this.INDENT.repeat(2) + 'mechanism.opmodeEnd()\n' + this.INDENT.repeat(2) + 'mechanism.opmode_end()\n' ); } if (this.getModuleType() === storageModule.ModuleType.OPMODE) { - // Add code to the Start method to call robot.opmodeStart. - this.classMethods[START_METHOD_NAME] = this.insertCodeToCallRobot(START_METHOD_NAME, 'opmodeStart'); + // Add code to the Start method to call robot.opmode_start. + this.classMethods[START_METHOD_NAME] = this.insertCodeToCallRobot(START_METHOD_NAME, 'opmode_start'); - // Add code to the periodic method to call robot.opmodePeriodic. - let periodicCode = this.insertCodeToCallRobot(PERIODIC_METHOD_NAME, 'opmodePeriodic'); + // Add code to the periodic method to call robot.opmode_periodic. + let periodicCode = this.insertCodeToCallRobot(PERIODIC_METHOD_NAME, 'opmode_periodic'); if (STEPS_METHOD_NAME in this.classMethods) { // Generate code to call the steps method after the user's code. periodicCode += this.INDENT + `self.${STEPS_METHOD_NAME}()\n`; } this.classMethods[PERIODIC_METHOD_NAME] = periodicCode; - // Add code to the End method to call robot.opmodeEnd. - this.classMethods[END_METHOD_NAME] = this.insertCodeToCallRobot(END_METHOD_NAME, 'opmodeEnd'); + // Add code to the End method to call robot.opmode_end. + this.classMethods[END_METHOD_NAME] = this.insertCodeToCallRobot(END_METHOD_NAME, 'opmode_end'); } const classMethods = []; @@ -469,14 +472,14 @@ export class ExtendedPythonGenerator extends PythonGenerator { classMethods.push(this.classMethods['__init__']) } - // Generate the defineHardware method next. - if ('defineHardware' in this.classMethods) { - classMethods.push(this.classMethods['defineHardware']) + // Generate the define_hardware method next. + if ('define_hardware' in this.classMethods) { + classMethods.push(this.classMethods['define_hardware']) } - // Generate the registerEventHandlers method next. + // Generate the register_event_handlers method next. if (this.registerEventHandlerStatements && this.registerEventHandlerStatements.length > 0) { - let registerEventHandlers = 'def registerEventHandlers(self):\n'; + let registerEventHandlers = 'def register_event_handlers(self):\n'; for (const registerEventHandlerStatement of this.registerEventHandlerStatements) { registerEventHandlers += this.INDENT + registerEventHandlerStatement; } @@ -485,7 +488,7 @@ export class ExtendedPythonGenerator extends PythonGenerator { // Generate the remaining methods. for (const name in this.classMethods) { - if (name === '__init__' || name === 'defineHardware') { + if (name === '__init__' || name === 'define_hardware') { continue; } classMethods.push(this.classMethods[name]) diff --git a/frontend/fields/field_gamepads.ts b/frontend/fields/field_gamepads.ts index e770acda..f8861bc5 100644 --- a/frontend/fields/field_gamepads.ts +++ b/frontend/fields/field_gamepads.ts @@ -784,8 +784,9 @@ export function createEventField(): Blockly.Field { } function getGamepad(gamepad: number): string { - // TODO: When python gets the userControls, this will remove the robot. from it, but for now we need to keep it to access the gamepads from the robot. - return 'self.robot.userControls.getGamepad(' + gamepad + ')'; + // TODO: When user_controls are implemented in RobotPy, adjust the following line as necesssary, + // but for now we need it to access the gamepads from the robot. + return 'self.robot.user_controls.get_gamepad(' + gamepad + ')'; } export function methodForButton(gamepad: number, button: string, action: string): string { diff --git a/frontend/modules/mechanism_start.json b/frontend/modules/mechanism_start.json index 113f1b65..738c6a9f 100644 --- a/frontend/modules/mechanism_start.json +++ b/frontend/modules/mechanism_start.json @@ -33,7 +33,7 @@ "params": [] }, "fields": { - "NAME": "opmodePeriodic" + "NAME": "opmode_periodic" } }, { diff --git a/frontend/storage/upgrade_project.ts b/frontend/storage/upgrade_project.ts index 33597976..237d6a4d 100644 --- a/frontend/storage/upgrade_project.ts +++ b/frontend/storage/upgrade_project.ts @@ -27,6 +27,9 @@ import * as storageModule from './module'; import * as storageModuleContent from './module_content'; import * as storageNames from './names'; import * as storageProject from './project'; +import { + upgrade_0_1_x_to_0_2_0 as upgrade_class_method_def_0_1_x_to_0_2_0 + } from '../blocks/mrc_class_method_def'; import * as workspaces from '../blocks/utils/workspaces'; declare const __APP_VERSION__: string; @@ -46,11 +49,14 @@ export async function upgradeProjectIfNecessary( return; } - // Major or minor version changed — add migration functions here for future transitions. + // Major or minor version changes. + + if (semver.lt(projectInfo.version, '0.2.0')) { + await upgradeFrom_0_1_x_to_0_2_0(storage, projectName); + } + + // Add more migration functions here for future transitions. // Example: - // if (semver.lt(projectInfo.version, '0.2.0')) { - // await upgradeFrom_0_1_0_to_0_2_0(storage, projectName, projectInfo); - // } // if (semver.lt(projectInfo.version, '0.3.0')) { // await upgradeFrom_0_2_0_to_0_3_0(storage, projectName, projectInfo); // } @@ -60,7 +66,6 @@ export async function upgradeProjectIfNecessary( await storageProject.saveProjectInfo(storage, projectName, projectInfo); } -// @ts-expect-error: declared but not used async function upgradeBlocksFiles( storage: commonStorage.Storage, projectName: string, @@ -122,7 +127,6 @@ function isOpMode(moduleType: storageModule.ModuleType): boolean { } /** Predicate: only Mechanism modules are affected. */ -// @ts-expect-error: declared but not used function isMechanism(moduleType: storageModule.ModuleType): boolean { return moduleType === storageModule.ModuleType.MECHANISM; } @@ -134,13 +138,11 @@ function isRobot(moduleType: storageModule.ModuleType): boolean { } /** Predicate: no modules are affected. */ -// @ts-expect-error: declared but not used function noModuleTypes(_moduleType: storageModule.ModuleType): boolean { return false; } /** Pre-upgrade passthrough: makes no changes to moduleContentText. */ -// @ts-expect-error: declared but not used function noPreupgrade(moduleContentText: string): string { return moduleContentText; } @@ -149,3 +151,15 @@ function noPreupgrade(moduleContentText: string): string { // @ts-expect-error: declared but not used function noUpgrade(_workspace: Blockly.Workspace): void { } + +async function upgradeFrom_0_1_x_to_0_2_0( + storage: commonStorage.Storage, + projectName: string): Promise { + // mrc_class_method_def blocks for mechanism 'opmodeStart' method need to be changed to 'opmode_start'. + // mrc_class_method_def blocks for mechanism 'opmodePeriodic' method need to be changed to 'opmode_periodic'. + // mrc_class_method_def blocks for mechanism 'opmodeEnd' method need to be changed to 'opmode_end'. + await upgradeBlocksFiles( + storage, projectName, + noModuleTypes, noPreupgrade, + isMechanism, upgrade_class_method_def_0_1_x_to_0_2_0); +} diff --git a/frontend/toolbox/event_category.ts b/frontend/toolbox/event_category.ts index 90645eba..e8525d67 100644 --- a/frontend/toolbox/event_category.ts +++ b/frontend/toolbox/event_category.ts @@ -64,7 +64,7 @@ class EventsCategory { // Add a block that lets the user define a new event. contents.push( new toolboxItems.Label(Blockly.Msg['CUSTOM_EVENTS_LABEL']), - createCustomEventBlock(storageNames.makeUniqueName('myEvent', eventNames))); + createCustomEventBlock(storageNames.makeUniqueName('my_event', eventNames))); // Get blocks for firing events defined in the current workspace. addFireEventBlocks(eventsFromWorkspace, contents); diff --git a/frontend/toolbox/lists_category.ts b/frontend/toolbox/lists_category.ts index fc5ed26b..81839448 100644 --- a/frontend/toolbox/lists_category.ts +++ b/frontend/toolbox/lists_category.ts @@ -47,7 +47,7 @@ export const getCategory = () => ({ type: 'variables_get', fields: { VAR: { - name: 'myList', + name: 'my_list', }, }, }, @@ -63,7 +63,7 @@ export const getCategory = () => ({ type: 'variables_get', fields: { VAR: { - name: 'myList', + name: 'my_list', }, }, }, @@ -79,7 +79,7 @@ export const getCategory = () => ({ type: 'variables_get', fields: { VAR: { - name: 'myList', + name: 'my_list', }, }, }, @@ -95,7 +95,7 @@ export const getCategory = () => ({ type: 'variables_get', fields: { VAR: { - name: 'myList', + name: 'my_list', }, }, }, @@ -111,7 +111,7 @@ export const getCategory = () => ({ type: 'variables_get', fields: { VAR: { - name: 'myList', + name: 'my_list', }, }, }, @@ -141,7 +141,7 @@ export const getCategory = () => ({ type: 'variables_get', fields: { VAR: { - name: 'myList', + name: 'my_list', }, }, }, diff --git a/frontend/toolbox/text_category.ts b/frontend/toolbox/text_category.ts index 4d4e9637..42e15371 100644 --- a/frontend/toolbox/text_category.ts +++ b/frontend/toolbox/text_category.ts @@ -63,7 +63,7 @@ export const getCategory = () => ({ type: 'variables_get', fields: { VAR: { - name: 'myText', + name: 'my_text', }, }, }, @@ -87,7 +87,7 @@ export const getCategory = () => ({ type: 'variables_get', fields: { VAR: { - name: 'myText', + name: 'my_text', }, }, }, @@ -103,7 +103,7 @@ export const getCategory = () => ({ type: 'variables_get', fields: { VAR: { - name: 'myText', + name: 'my_text', }, }, }, diff --git a/package.json b/package.json index 12a7aab0..d29c9bf1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "system_core_blocks", - "version": "0.1.1", + "version": "0.2.0", "homepage": "/blocks", "private": true, "dependencies": { diff --git a/python_tools/json_util.py b/python_tools/json_util.py index a190f33c..d061a83d 100644 --- a/python_tools/json_util.py +++ b/python_tools/json_util.py @@ -523,6 +523,9 @@ def _processComponent(self, class_data): # looks at doc string and/or parameter type aliases to tell whether this is # a component and what the args are. + # TODO(lizlooney): When RobotPy is changed to use snake case, update the following code. + # Argument and function names might have changed. + class_name = class_data[_KEY_CLASS_NAME] if class_name == 'wpilib.ExpansionHubMotor': @@ -535,7 +538,7 @@ def _processComponent(self, class_data): args[1][_KEY_ARGUMENT_NAME] == 'channel'): found_constructor = True component_args = [] - component_args.append(self._createArgData('expansionHubMotor', 'SYSTEMCORE_USB_PORT__EXPANSION_HUB_MOTOR_PORT')) + component_args.append(self._createArgData('expansion_hub_motor', 'SYSTEMCORE_USB_PORT__EXPANSION_HUB_MOTOR_PORT')) constructor_data[_KEY_COMPONENT_ARGS] = component_args constructor_data[_KEY_IS_COMPONENT] = True if not found_constructor: @@ -566,7 +569,7 @@ def _processComponent(self, class_data): args[1][_KEY_ARGUMENT_NAME] == 'channel'): found_constructor = True component_args = [] - component_args.append(self._createArgData('expansionHubServo', 'SYSTEMCORE_USB_PORT__EXPANSION_HUB_SERVO_PORT')) + component_args.append(self._createArgData('expansion_hub_servo', 'SYSTEMCORE_USB_PORT__EXPANSION_HUB_SERVO_PORT')) constructor_data[_KEY_COMPONENT_ARGS] = component_args constructor_data[_KEY_IS_COMPONENT] = True if not found_constructor: @@ -593,7 +596,7 @@ def _processComponent(self, class_data): args[0][_KEY_ARGUMENT_NAME] == 'channel'): found_constructor = True component_args = [] - component_args.append(self._createArgData('smartIoPort', 'SYSTEMCORE_SMART_IO_PORT')) + component_args.append(self._createArgData('smart_io_port', 'SYSTEMCORE_SMART_IO_PORT')) constructor_data[_KEY_COMPONENT_ARGS] = component_args constructor_data[_KEY_IS_COMPONENT] = True if not found_constructor: @@ -619,7 +622,7 @@ def _processComponent(self, class_data): args[2][_KEY_ARGUMENT_NAME] == 'expectedZero'): found_constructor = True component_args = [] - component_args.append(self._createArgData('smartIoPort', 'SYSTEMCORE_SMART_IO_PORT')) + component_args.append(self._createArgData('smart_io_port', 'SYSTEMCORE_SMART_IO_PORT')) component_args.append(self._createArgData(args[1][_KEY_ARGUMENT_NAME], self._getClassName(args[1][_KEY_ARGUMENT_TYPE]), '1.0')) component_args.append(self._createArgData(args[2][_KEY_ARGUMENT_NAME], self._getClassName(args[2][_KEY_ARGUMENT_TYPE]), '0.0')) constructor_data[_KEY_COMPONENT_ARGS] = component_args @@ -646,7 +649,7 @@ def _processComponent(self, class_data): args[2][_KEY_ARGUMENT_NAME] == 'offset'): found_constructor = True component_args = [] - component_args.append(self._createArgData('smartIoPort', 'SYSTEMCORE_SMART_IO_PORT')) + component_args.append(self._createArgData('smart_io_port', 'SYSTEMCORE_SMART_IO_PORT')) component_args.append(self._createArgData(args[1][_KEY_ARGUMENT_NAME], self._getClassName(args[1][_KEY_ARGUMENT_TYPE]), args[1][_KEY_ARGUMENT_DEFAULT_VALUE])) component_args.append(self._createArgData(args[2][_KEY_ARGUMENT_NAME], self._getClassName(args[2][_KEY_ARGUMENT_TYPE]), args[2][_KEY_ARGUMENT_DEFAULT_VALUE])) constructor_data[_KEY_COMPONENT_ARGS] = component_args @@ -670,7 +673,7 @@ def _processComponent(self, class_data): args[0][_KEY_ARGUMENT_NAME] == 'channel'): found_constructor = True component_args = [] - component_args.append(self._createArgData('smartIoPort', 'SYSTEMCORE_SMART_IO_PORT')) + component_args.append(self._createArgData('smart_io_port', 'SYSTEMCORE_SMART_IO_PORT')) constructor_data[_KEY_COMPONENT_ARGS] = component_args constructor_data[_KEY_IS_COMPONENT] = True if not found_constructor: @@ -694,7 +697,7 @@ def _processComponent(self, class_data): args[2][_KEY_ARGUMENT_NAME] == 'expectedZero'): found_constructor = True component_args = [] - component_args.append(self._createArgData('smartIoPort', 'SYSTEMCORE_SMART_IO_PORT')) + component_args.append(self._createArgData('smart_io_port', 'SYSTEMCORE_SMART_IO_PORT')) component_args.append(self._createArgData(args[1][_KEY_ARGUMENT_NAME], self._getClassName(args[1][_KEY_ARGUMENT_TYPE]), '1')) component_args.append(self._createArgData(args[2][_KEY_ARGUMENT_NAME], self._getClassName(args[2][_KEY_ARGUMENT_TYPE]), '0')) constructor_data[_KEY_COMPONENT_ARGS] = component_args @@ -752,7 +755,7 @@ def _processComponent(self, class_data): args[0][_KEY_ARGUMENT_NAME] == 'channel'): found_constructor = True component_args = [] - component_args.append(self._createArgData('smartIoPort', 'SYSTEMCORE_SMART_IO_PORT')) + component_args.append(self._createArgData('smart_io_port', 'SYSTEMCORE_SMART_IO_PORT')) constructor_data[_KEY_COMPONENT_ARGS] = component_args constructor_data[_KEY_IS_COMPONENT] = True if not found_constructor: diff --git a/runtime_python/blocks_base_classes/mechanism.py b/runtime_python/blocks_base_classes/mechanism.py index 8aed6231..f896348e 100644 --- a/runtime_python/blocks_base_classes/mechanism.py +++ b/runtime_python/blocks_base_classes/mechanism.py @@ -4,32 +4,32 @@ class Mechanism: def __init__(self): - # In self.eventHandlers, the keys are the event names, the values are a list of handlers. - self.eventHandlers = {} + # In self.event_handlers, the keys are the event names, the values are a list of handlers. + self.event_handlers = {} - def registerEventHandler(self, eventName: str, eventHandler: Callable) -> None: - if eventName in self.eventHandlers: - self.eventHandlers[eventName].append(eventHandler) + def register_event_handler(self, event_name: str, event_handler: Callable) -> None: + if event_name in self.event_handlers: + self.event_handlers[event_name].append(event_handler) else: - self.eventHandlers[eventName] = [eventHandler] + self.event_handlers[event_name] = [event_handler] - def unregisterEventHandler(self, eventName: str, eventHandler: Callable) -> None: - if eventName in self.eventHandlers: - if eventHandler in self.eventHandlers[eventName]: - self.eventHandlers[eventName].remove(eventHandler) - if not self.eventHandlers[eventName]: - del self.eventHandlers[eventName] + def unregister_event_handler(self, event_name: str, event_handler: Callable) -> None: + if event_name in self.event_handlers: + if event_handler in self.event_handlers[event_name]: + self.event_handlers[event_name].remove(event_handler) + if not self.event_handlers[event_name]: + del self.event_handlers[event_name] - def fireEvent(self, eventName: str, *args) -> None: - if eventName in self.eventHandlers: - for eventHandler in self.eventHandlers[eventName]: - eventHandler(*args) + def fire_event(self, event_name: str, *args) -> None: + if event_name in self.event_handlers: + for event_handler in self.event_handlers[event_name]: + event_handler(*args) - def opmodeStart(self) -> None: + def opmode_start(self) -> None: pass - def opmodePeriodic(self) -> None: + def opmode_periodic(self) -> None: pass - def opmodeEnd(self) -> None: + def opmode_end(self) -> None: pass diff --git a/runtime_python/blocks_base_classes/user_controls.py b/runtime_python/blocks_base_classes/user_controls.py index 6dc358a3..b0c49373 100644 --- a/runtime_python/blocks_base_classes/user_controls.py +++ b/runtime_python/blocks_base_classes/user_controls.py @@ -7,5 +7,5 @@ class DefaultUserControls: def __init__(self): self.m_gamepads = [wpilib.Gamepad(i) for i in range(JOYSTICK_PORTS)] - def getGamepad(self, port: int) -> wpilib.Gamepad: + def get_gamepad(self, port: int) -> wpilib.Gamepad: return self.m_gamepads[port]