text:
JLCPCB's PCA preview shows Hillside 46 components misplaced

Hello!
Thanks a lot for this wonderful looking keyboard, and the very helpful detailed instructions!
I'm following the instructions on the Ordering Hillside 52 or 46 page, in order to order a Hillside 46 from JLCPCB.
I'm following the steps detailed in the doc step by step, but after uploading the BOM and top_boards.csv, JLCPCB's preview shows the components positioned completely off the PCB:

This seems to be the only preview JLCPCB shows before placing the order. I've redone the steps three times and I don't think I've missed anything. Is it the case that I've missed anything, or is there an issue with JLCPCB or with the instructions?
Steps to reproduce

Download hillside46-gerber-and-pcba_0.1.0 from Releases hill46_v0.1.0.

On JLCPCB, follow the instructions from How to Order Five PCBA Keyboards
Side note: The instructions say "Dimensions: 100 x 143 mm". But after uploading the Gerber file, dimensions are pre-populated and are slightly different: 142.49 width, 99.87 height.

At the 'Save to Cart' step, which reads ...

The preview should show components placed and rotated over spots on the board that look meant for them, in terms of silkscreen lines around them and traces leading to them. The engineers will ensure the final placement, and you will confirm at DFM Analysis later.

... the components on the preview are placed away from the PCB board.

Looking at other people's experience, it may be an issue with JLCPCB's viewer, and the assembly may come back fine:
https://www.eevblog.com/forum/manufacture/jlcpcb-smt-weird-issue-with-part-placements/

JLCPCB have posted a blog post which seems to be about that issue, with reassurance that it's fine:
https://github.com/JLCPCB/JLCPCB-SMT-Assembly-Components-orientation-fix
I'm closing the issue as I don't expect this is a problem with the instructions in this repo.

On the note of the part misalignment, the placement for U2 isn't very clear so I'm concerned that the orientation might be incorrect when the placement is imported.
Would it be possible to please include a note or picture somewhere in the guide to show the correct orientation of U2 on the top and bottom boards?

I had this too, though not in the preview but confirmation via email. I used 'confirm parts placement' option (as recommended) and they showed their skills by automatically sending me pictures of corrected placements. They won't beginn the production if you don't confirm that so my guess is you won't lose your money by just trying.
The final product works as intended. (hillside52)

Hello!
I've now placed and received my PCB Assembly order from JLCPCB.
I can confirm that there was no issue at all.
Specifically, in spite of the fact that the components were mis-positioned (a rotation issue) on the preview at the time of ordering:

I received an email a few hours after ordering to ask me to check the corrected positioning. On that new visualisation the positioning was correct. If it hadn't been, I would have been able to ask for changes.
The PCB I've received has the parts positioned in the correct way.

So, I'm closing this issue.
Also, I want to say that I'm very grateful for and impressed by both the design of Hillside, but also the thoughtful comprehensive documentation. Both were reasons why I've chosen to build Hillside 46 as my first keyboard, and I'm very excited about it. It's very close to the perfect keyboard for me. Thanks!

authors: Max-Stevens auipga jfhector

repo: mmccoyd/hillside


text:
QuickConvertorV2.ahk Error

When attempting to convert code:
`#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn  ; Enable warnings to assist with detecting common errors.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.
; Control == ^ Alt == ! Shift == +
; Main Program
; Generic Variables
global currentVersion := "Version .7"
global createNewX := 0
global createNewY := 0
global extraDelayValue := 0
global extraTabDelayValue := 0
global activeExcelPath := 0
; Save clipboard contents then clear, set ClipboardTimeout to allow for longer delay if clipboard is locked.
#ClipboardTimeout, 2000
clipSaved := ClipboardAll
Clipboard =
; Overlay GUI Setup
OSDColour2 = EAAA99  ; Can be any RGB color (it will be made transparent below).
Gui, 2: +LastFound +AlwaysOnTop -Caption +ToolWindow  ; +ToolWindow avoids a taskbar button and an alt-tab menu item.
Gui, 2:Font, s128, Times New Roman  ; Set a large font size (32-point).
Gui, 2:Add, Text, vOSDControl cBlue x60 y200, XXXXXXYYYYYY ; XX & YY serve to auto-size the window; add some random letters to enable a longer string of text (but it might not fit on the screen).
Gui, 2:Color, %OSDColour2%
WinSet, TransColor, %OSDColour2% 110 ; Make all pixels of this color transparent and make the text itself translucent (150)
Gui, 2:Show, NoActivate, OSDGui
Gui, 2:Show, Hide
; Check for and create a store file if necessary
createStoreFile()
; Load default gui values for display along with saved mouse creation coords if they exist, creates a storage file if one does not exist.
loadDefaultGuiValue()
; Generate GUI for Gathering Ticket Info
Gui, New,, Bulk SCTask Creation Tool by nope@nope.nope %currentVersion%
gui, add, text,, * Starting on Excel Row
gui, add, text,, * Ending on Excel Row
gui, add, text,, Extra Delay (1000 == 1 Second)
gui, add, text,, Tab Extra Delay (1000 == 1 Second)
gui, add, text,, * Requested for someone else
gui, add, text,, Requested for
gui, add, text,, * Phone Number
gui, add, text,, Extension
gui, add, text,, * Building Number
gui, add, text,, * Room Number
gui, add, text,, * Requested for Employee Type
gui, add, text,, * Brief Description
gui, add, text, r7.3, * Description
gui, add, text,, System Name, EE Number, or Hostname
gui, add, text,, Assignment Group
gui, add, text,, State
gui, add, text,, Assigned To
gui, add, button,, Choose Excel File
gui, add, edit, number vstartingRow w400 ym, %guiDisplayStartingRow%
gui, add, edit, number vendingRow w400, %guiDisplayEndingRow%
gui, add, edit, number vextraDelayValue w400, %guiDisplayextraDelay%
gui, add, edit, number vextraTabDelayValue w400, %guiDisplayextraTabDelay%
gui, add, DropDownList, AltSubmit vrequestedForSomeoneElseDDL w400, 1-Yes|2-No||
gui, add, edit, vrequestedFor w400, %guiDisplayRequestedFor%
gui, add, edit, vphoneNumber w400, %guiDisplayPhoneNumber%
gui, add, edit, vphoneExtension w400, %guiDisplayPhoneExtension%
gui, add, edit, vbuildingNumber w400, %guiDisplayBuildingNumber%
gui, add, edit, vroomNumber w400, %guiDisplayRoomNumber%
gui, add, DropDownList, AltSubmit vrequestedForEmployeeTypeDDL w400, 1-Employee||2-Contractor|3-HPT / Trainee / Resident / Student|4-Volunteer / WOC / Non-VA Personnel|5- Temporary Account
gui, add, edit, vbriefDescription w400, %guiDisplayBriefDescription%
gui, add, edit, r6 w400 hscroll vdescription, %guiDisplayDescription%
gui, add, edit, vsystemName w400, %guiDisplaySystemName%
gui, add, edit, vassignmentGroup w400, %guiDisplayAssignmentGroup%
gui, add, DropDownList, AltSubmit vstateDDL w400, Pending|Open||Work In Progress|Closed Complete|Closed Incomplete|Closed Skipped
gui, add, edit, vassignedTo w400, %guiDisplayAssignedTo%
gui, add, button, vrunLoop, Run Loop
GuiControl, Disable, runLoop
gui, add, button, default ym, Load Last Used Info
gui, add, button,, Help Me
gui, add, text,,
gui, add, button,, Load Previous Template
gui, add, button,, Save Current Template
Gui, Show, xcenter ycenter
return
; Exit script with Escape key
Esc::
xl.Quit
xl := ""
Clipboard := clipSaved
clipSaved =
ExitApp
; Exit script when gui closed
GuiClose:
xl.Quit
xl := ""
Clipboard := clipSaved
clipSaved =
ExitApp
; Continue main program after OK button is pressed
ButtonRunLoop:
; Gather current Gui Values
gui, Submit
gui, Destroy
; Add GUI Overlay to provide status of ticket loop
OSD("Starting Ticket Loop.")
; Example call: OSD("I'm an aeroplane", "Red", "Arial", "14")
; Save values to last used
saveGuiValueToStoreFile()
; Prime information for ticket loop
rowCount := startingRow - 1
loopCount := 0
ticketCount := endingRow - startingRow + 1
stateDDL := stateDDL - 2
; Prepare Excel File for use
xl := ComObjCreate("Excel.Application")
global xlbook := xl.Workbooks.Open(activeExcelPath)
; For Funsies
; SoundPlay, %A_ScriptDir%\soundclip.mp3
loop %ticketCount%
{
; Give time for user to activate SNOW window on first loop, and page load for next loops.
Sleep 5000 + extraDelayValue
; Increment loop variables
rowCount := rowCount + 1
loopCount := loopCount + 1

; Update Loop Overlay for current iteration
newOverlayText := "Ticket " loopcount " of " ticketCount
OSD(newOverlayText)

; Send Webpage URL
Send !d
Sleep 100 + extraDelayValue
weblink := "https://some.very.long.web.link"
Send %weblink%
Sleep 1000 + extraDelayValue
Send {Enter}
Sleep 5000 + extraDelayValue
; Requested For Drop Down List, this is default starting field on web page load
downLoop(Abs(requestedForSomeoneElseDDL))
Sleep 100 + extraDelayValue
; Branch based on if requested for another user
if (requestedForSomeoneElseDDL > 1)
{
    ; Amount of tabs between Requested For DDL and Requested For Phone Number, adjust if SNOW changes
    tabLoop(3)
    sleep 100 + extraDelayValue
}
else if (requestedForSomeoneElseDDL > 2)
{
    ; Amount of tabs between Requested For DDL and Requested For, adjust if SNOW changes
    tabLoop(1)
    sleep 100 + extraDelayValue
    ; Requested For Field
    sendValue(requestedFor, rowCount)
    ; Amount of tabs between Requested For and Requested for Phone Number, adjust if SNOW changes
    tabLoop(2)
    sleep 100 + extraDelayValue
}
; Requested For Phone Number Field
sendValue(phoneNumber, rowCount)
sleep 100 + extraDelayValue
; Amount of tabs between Requsted For Phone Number and Requested For Phone Extension, adjust if SNOW changes
tabLoop(2)
sleep 100 + extraDelayValue
; Requested for Phone Extension Field
sendValue(phoneExtension, rowCount)
; Amount of tabs between Requsted For Phone Extension and Requested For Building Number, adjust if SNOW changes
tabLoop(3)
sleep 100 + extraDelayValue
; Requested for Building Number Field
sendValue(buildingNumber, rowCount)
; Amount of tabs between Requsted For Building Number and Requested For Room Number, adjust if SNOW changes
tabLoop(1)
sleep 100 + extraDelayValue
; Requested for Building Number Field
sendValue(roomNumber, rowCount)
; Amount of tabs between Requsted For Room Number and Requested For Employee Type, adjust if SNOW changes
tabLoop(1)
sleep 100 + extraDelayValue
; Requested for Employee Type DDL
downLoop(Abs(requestedForEmployeeTypeDDL))
Sleep 100 + extraDelayValue
; Amount of tabs between Requsted For Employee Type and Brief Description, adjust if SNOW changes
tabLoop(3)
sleep 100 + extraDelayValue
; Brief Description Field
sendValue(briefDescription, rowCount)
; Amount of tabs between Brief Description and Description, adjust if SNOW changes
tabLoop(2)
sleep 100 + extraDelayValue
; Description Field
sendValue(description, rowCount)
; Amount of tabs between Description and System Name, adjust if SNOW changes
tabLoop(2)
sleep 100 + extraDelayValue
; System Name Field
sendValue(systemName, rowCount)
; Amount of tabs between System Name and Request Assignment Group, adjust if SNOW changes
tabLoop(2)
sleep 100 + extraDelayValue
; Assignment Group
sendValue(assignmentGroup, rowCount)
sleep 500 + extraDelayValue
; Amount of tabs between Request Assignment Group and submit, adjust if SNOW changes
tabLoop(1)
sleep 100 + extraDelayValue
; Submit Button
Sleep 1000 + extraDelayValue
send, {Enter}
Sleep 5000 + extraDelayValue
; Amount of tabs to Navigate to RITM Page, adjust if SNOW changes
tabLoop(6)
sleep 100 + extraDelayValue
send {Enter}
sleep 5000 + extraDelayValue
; Amount of tabs to Navigate to SCTask Page, adjust if SNOW changes
tabLoop(81)
sleep 100 + extraDelayValue
send {Enter}
sleep 5000 + extraDelayValue
; Amount of tabs to State Drop Down List, adjust if SNOW changes
tabLoop(3)
; State Drop Down List
; State starts on open, the bottom of the list. I adjust that above with a -2, then logic follows to complete.
if (stateDDL > 0)
{
    downLoop(stateDDL)
    Sleep 100 + extraDelayValue
}
else if (stateDDL < 0)
{
    upLoop(Abs(stateDDL))
    Sleep 100 + extraDelayValue
}
else if (stateDDL = 0)
{
    sleep 100 +extraDelayValue
}
; Amount of tabs between State Drop Down List and Assigned to, adjust if SNOW changes
tabLoop(2)
; Assigned to Field
sendValue(assignedTo, rowCount)
sleep 500 + extraDelayValue
; Amount of tabs between Assigned to and Short Description, adjust if SNOW changes
tabLoop(1)
; Short Description to Field
sendValue(briefDescription, rowCount)
sleep 100 + extraDelayValue
; Amount of tabs to get back to update button at top of page, adjust if SNOW changes
shiftTabLoop(12)
sleep 500 + extraDelayValue
send {Enter}

}
; Clear Excel ComObject Call
xl.Quit
xl := ""
Clipboard := clipSaved
clipSaved =
; Exit program here all tickets completed
ExitApp
; Building Area
; function stump
; But what does it do? - Yarusch
; Current State == Not Functional
basicFunction(vari1, vari2)
{
}
; Completed Functions and subroutines
; Send Tabs based on value given, cleans code above to be more readable
; Current State == Functional
tabLoop(tabCount)
{
loop %tabCount%
{
SendInput, {Tab}
Sleep %extraTabDelayValue%
}
return
}
; Send Shift Tabs based on value given, cleans code above to be more readable
; Current State == Functional
shiftTabLoop(tabCount)
{
loop %tabCount%
{
SendInput, +{Tab}
Sleep %extraTabDelayValue%
}
return
}
; Send the value provided, cleans code above to be more readable
; Current State == Functional
sendValue(sendValue, sendRow)
{
value := checkDynamicSend(sendValue, sendRow)
sendValueClipboard(value)
value =
sleep 100 + extraDelayValue
return
}
; Checks value for strength length then sends via clipboard or direct depending on length.
; Current State == Complete and Functional
sendValueClipboard(sendValue)
{
if (StrLen(sendValue) > 100)
{
clipboard = %sendValue%
ClipWait, 2
if ErrorLevel
{
MsgBox, The attempt to copy text onto the clipboard failed. Take note of which item loop broke on below. Press escape to break out of loop.
xl.Quit
xl := ""
Clipboard := clipSaved
clipSaved =
ExitApp
}
send, ^v
sleep 100 + extraDelayValue
clipboard =
}
else
{
send, %sendValue%
sleep 100 + extraDelayValue
}
return
}
; Run routine when load last file button is pressed
; All working except for updating the values of the coords for create new and submit
ButtonLoadLastUSedInfo:
loadGuiValuesFromStoreFile()
updateGuiValues()
return
; Parses a string and returns the value including dynamic information pulled from dynamic excel switch based on switch in the string and current row being used in loop.
; Current State = Complete and Functional
translateDynamicExcel(translateString, currentRow)
{
global
translatedOutput := ""
Loop, parse, translateString, `,
{
length := StrLen(A_LoopField)
if length = 1
{
if A_LoopField is Alpha
{
cellString = %A_LoopField%%currentRow%
functionValue := xlbook.Sheets(1).Range(cellString).Text
translatedOutput = %translatedOutput% %functionValue%
}
else
{
translatedOutput = %translatedOutput%%A_LoopField%
}
}
else
{
translatedOutput = %translatedOutput%%A_LoopField%
}
}
return translatedOutput
}
; LoadValues from Stored File if it exists, creates it if it doesn't
; Current State = Complete and Functional
loadGuiValuesFromStoreFile()
{
global
createStoreFile()
IniRead, guiDisplayStartingRow, lastUsedReq.ini, templateValues, startingRow, %A_Space%
IniRead, guiDisplayEndingRow, lastUsedReq.ini, templateValues, endingRow, %A_Space%
IniRead, guiDisplayextraDelay, lastUsedReq.ini, templateValues, extraDelayValue, %A_Space%
IniRead, guiDisplayextraTabDelay, lastUsedReq.ini, templateValues, extraTabDelayValue, %A_Space%
IniRead, guiDisplayRequestedForDDL, lastUsedReq.ini, templateValues, requestedForSomeoneElseDDL, %A_Space%
IniRead, guiDisplayRequestedFor, lastUsedReq.ini, templateValues, requestedFor, %A_Space%
IniRead, guiDisplayPhoneNumber, lastUsedReq.ini, templateValues, phoneNumber, %A_Space%
IniRead, guiDisplayPhoneExtension, lastUsedReq.ini, templateValues, phoneExtension, %A_Space%
IniRead, guiDisplayBuildingNumber, lastUsedReq.ini, templateValues, buildingNumber, %A_Space%
IniRead, guiDisplayRoomNumber, lastUsedReq.ini, templateValues, roomNumber, %A_Space%
IniRead, guiDisplayRequestedForEmployeeTypeDDL, lastUsedReq.ini, templateValues, requestedForEmployeeTypeDDL, %A_Space%
IniRead, guiDisplayBriefDescription, lastUsedReq.ini, templateValues, briefDescription, %A_Space%
IniRead, readDescription, lastUsedReq.ini, templateValues, description, %A_Space%
guiDisplayDescription := StrReplace(readDescription, "", "`n")
IniRead, guiDisplaySystemName, lastUsedReq.ini, templateValues, systemName, %A_Space%
IniRead, guiDisplayAssignmentGroup, lastUsedReq.ini, templateValues, assignmentGroup, %A_Space%
IniRead, guiDisplayStateDDL, lastUsedReq.ini, templateValues, stateDDL, %A_Space%
IniRead, guiDisplayAssignedTo, lastUsedReq.ini, templateValues, assignedTo, %A_Space%
return
}
; Update current fields in gui to reflect values of variables.
; Current State = Complete and Functional
updateGuiValues()
{
global
GuiControl,, startingRow, %guiDisplayStartingRow%
GuiControl,, endingRow, %guiDisplayEndingRow%
GuiControl,, extraDelayValue, %guiDisplayextraDelay%
GuiControl,, extraTabDelayValue, %guiDisplayextraTabDelay%
GuiControl, Choose, requestedForSomeoneElseDDL, %guiDisplayRequestedForDDL%
GuiControl,, requestedFor, %guiDisplayRequestedFor%
GuiControl,, phoneNumber, %guiDisplayPhoneNumber%
GuiControl,, phoneExtension, %guiDisplayPhoneExtension%
GuiControl,, buildingNumber, %guiDisplayBuildingNumber%
GuiControl,, roomNumber, %guiDisplayRoomNumber%
GuiControl, Choose, requestedForEmployeeTypeDDL, %guiDisplayRequestedForEmployeeTypeDDL%
GuiControl,, briefDescription, %guiDisplaybriefDescription%
GuiControl,, description, %guiDisplayDescription%
GuiControl,, systemName, %guiDisplaySystemName%
GuiControl,, assignmentGroup, %guiDisplayAssignmentGroup%
GuiControl, Choose, stateDDL, %guiDisplayStateDDL%
GuiControl,, assignedTo, %guiDisplayAssignedTo%
Return
}
; Test a string provided and return boolean value if dynamic excel switch is in string.
; Dynamic Excel Swith = ,x, where x is the letter representing the column to pull information from.
; Current State = Complete and Functional
containsExcelDynamic(contentString)
{
isDynamic = False
Loop, parse, contentString, `,
{
length := StrLen(A_LoopField)
if length = 1
{
isDynamic = True
}
}
return isDynamic
}
; Creates the default store file if it doesn't exist
; Current State = Complete and Functional
createStoreFile()
{
global
if !FileExist(A_ScriptDir "\lastUsedReq.ini")
{
IniWrite, "Which excel row to start on?", lastUsedReq.ini, templateValues, startingRow
IniWrite, "Which excel row is the last one to be used?", lastUsedReq.ini, templateValues, endingRow
IniWrite, "Must be a number minimum 0 suggested 100", lastUsedReq.ini, templateValues, extraDelayValue
IniWrite, "Must be a number minimum 0", lastUsedReq.ini, templateValues, extraTabDelayValue
IniWrite, 2, lastUsedReq.ini, templateValues, requestedForEmployeeTypeDDL
IniWrite, "Leave Blank for self request (I'd use this), use exact name FirstName LastName if for another", lastUsedReq.ini, templateValues, requestedFor
IniWrite, "10 or 11 Digit Number", lastUsedReq.ini, templateValues, phoneNumber
IniWrite, "Extension, can be left blank", lastUsedReq.ini, templateValues, phoneExtension
IniWrite, "Building Number", lastUsedReq.ini, templateValues, buildingNumber
IniWrite, "Room Number", lastUsedReq.ini, templateValues, roomNumber
IniWrite, 1, lastUsedReq.ini, templateValues, requestedForSomeoneElseDDL
IniWrite, "Short Decription of Case", lastUsedReq.ini, templateValues, briefDescription
IniWrite, "Description of Case", lastUsedReq.ini, templateValues, description
IniWrite, "System Name or EE Number", lastUsedReq.ini, templateValues, systemName
IniWrite, "Assignment Group as it appears in SNOW, ie group", lastUsedReq.ini, templateValues, assignmentGroup
IniWrite, 2, lastUsedReq.ini, templateValues, stateDDL
IniWrite, "Assigned to use full @nope.nope email address for best results", lastUsedReq.ini, templateValues, assignedTo
}
return
}
; Save values to the storage file to be used later
; Current State = Complete and Functional
saveGuiValueToStoreFile()
{
global
IniWrite, %startingRow%, lastUsedReq.ini, templateValues, startingRow
IniWrite, %endingRow%, lastUsedReq.ini, templateValues, endingRow
IniWrite, %extraDelayValue%, lastUsedReq.ini, templateValues, extraDelayValue
IniWrite, %extraTabDelayValue%, lastUsedReq.ini, templateValues, extraTabDelayValue
IniWrite, %requestedForSomeoneElseDDL%, lastUsedReq.ini, templateValues, requestedForSomeoneElseDDL
IniWrite, %requestedFor%, lastUsedReq.ini, templateValues, requestedFor
IniWrite, %phoneNumber%, lastUsedReq.ini, templateValues, phoneNumber
IniWrite, %phoneExtension%, lastUsedReq.ini, templateValues, phoneExtension
IniWrite, %roomNumber%, lastUsedReq.ini, templateValues, roomNumber
IniWrite, %buildingNumber%, lastUsedReq.ini, templateValues, buildingNumber
IniWrite, %requestedForEmployeeTypeDDL%, lastUsedReq.ini, templateValues, requestedForEmployeeTypeDDL
IniWrite, %briefDescription%, lastUsedReq.ini, templateValues, briefDescription
IniWrite, % StrReplace(description, "`n",""), lastUsedReq.ini, templateValues, description
IniWrite, %systemName%, lastUsedReq.ini, templateValues, systemName
IniWrite, %assignmentGroup%, lastUsedReq.ini, templateValues, assignmentGroup
IniWrite, %stateDDL%, lastUsedReq.ini, templateValues, stateDDL
IniWrite, %assignedTo%, lastUsedReq.ini, templateValues, assignedTo
return
}
; Check which value to send based on if there is dynamic content or not, then return the value that should be sent as a string.
; Current State = Complete and Functional
checkDynamicSend(contentString, excelRow)
{
isDynamic := containsExcelDynamic(contentString)
translatedContent := ""
if (%isDynamic% = False)
{
translatedContent = %contentString%
}
else
{
translatedContent := translateDynamicExcel(contentString, excelRow)
}
return %translatedContent%
}
; Repeats down key action with pauses based on variable provided
; Current State = Complete and Functional
downLoop(loopCount)
{
SendInput, {Down}
Sleep 300 + extraDelayValue
if (loopCount > 1)
{
downLoop(loopcount - 1)
}
return
}
; Repeats up key action with pauses based on variable provided
; Current State = Complete and Functional
upLoop(loopCount)
{
SendInput, {Up}
Sleep 300 + extraDelayValue
if (loopCount > 1)
{
upLoop(loopcount - 1)
}
return
}
; Load default values to populate in GUI along with stored values for click positions
; Current State = Complete and Functional
loadDefaultGuiValue()
{
global
guiDisplayStartingRow := "Which excel row to start on?"
guiDisplayEndingRow := "Which excel row is the last one to be used?"
guiDisplayextraDelay := "Must be a number, minimum 0, suggested 100"
guiDisplayextraTabDelay := "Must be a number, minimum 0"
guiDisplayPhoneNumber := "10 or 11 Digit Number, suggested (xxx) yyy-zzzz format"
guiDisplayPhoneExtension := "Extension, can be left blank"
guiDisplayBuildingNumber := "Building Number"
guiDisplayRoomNumber := "Room Number"
guiDisplayBriefDescription := "Short Decription of Case"
guiDisplayDescription := "Description of Case"
guiDisplaysystemName := "System Name or EE Number"
guiDisplayAssignmentGroup := "Assignment Group as it appears in SNOW, ie group"
guiDisplayAssignedTo := "Assigned to use full @nope.nope email address for best results"
return
}
; Uses file prompt to allow use to select the excel file then enables the run loop button.
; Current State == Complete and Functional
ButtonChooseExcelFile:
FileSelectFile, activeExcelPath
GuiControl, Enable, runLoop
return
; Loads tutorial for user as a pop box
; Current State == Complete and Functional
ButtonHelpMe:
msgbox, "So this will actually be the tutorial for the incident version of the tool cause I haven't written a task one.`nBut most of the stuff is the same."
run https://some.other.web.link
; Loads previous template via file open box.
; Current State == Complete and Functional
ButtonLoadPreviousTemplate:
FileSelectFile, toOpenFileName, 3, %A_WorkingDir%, Open Template, Template (*.ini)
toOpenFileName := StrReplace(toOpenFileName, ".ini")
IniRead, guiDisplayStartingRow, %toOpenFileName%.ini, templateValues, startingRow, %A_Space%
IniRead, guiDisplayEndingRow, %toOpenFileName%.ini, templateValues, endingRow, %A_Space%
IniRead, guiDisplayextraDelay, %toOpenFileName%.ini, templateValues, extraDelayValue, %A_Space%
IniRead, guiDisplayextraTabDelay, %toOpenFileName%.ini, templateValues, extraTabDelayValue, %A_Space%
IniRead, guiDisplayRequestedForSomeoneElseDDL, %toOpenFileName%.ini, templateValues, requestedForSomeoneElseDDL, %A_Space%
IniRead, guiDisplayPhoneNumber, %toOpenFileName%.ini, templateValues, phoneNumber, %A_Space%
IniRead, guiDisplayPhoneExtension, %toOpenFileName%.ini, templateValues, phoneExtension, %A_Space%
IniRead, guiDisplayBuildingNumber, %toOpenFileName%.ini, templateValues, buildingNumber, %A_Space%
IniRead, guiDisplayRoomNumber, %toOpenFileName%.ini, templateValues, roomNumber, %A_Space%
IniRead, guiDisplayRequestedForEmployeeTypeDDL, %toOpenFileName%.ini, templateValues, requestedForEmployeeTypeDDL, %A_Space%
IniRead, guiDisplaybriefDescription, %toOpenFileName%.ini, templateValues, briefDescription, %A_Space%
IniRead, readDescription, %toOpenFileName%.ini, templateValues, description, %A_Space%
guiDisplayDescription := StrReplace(readDescription, "", "`n")
IniRead, guiDisplaysystemName, %toOpenFileName%.ini, templateValues, systemName, %A_Space%
IniRead, guiDisplayAssignmentGroup, %toOpenFileName%.ini, templateValues, assignmentGroup, %A_Space%
IniRead, guiDisplaystateDDL, %toOpenFileName%.ini, templateValues, stateDDL, %A_Space%
IniRead, guiDisplayAssignedTo, %toOpenFileName%.ini, templateValues, assignedTo, %A_Space%
updateGuiValues()
return
; Saves current template via file save box
; Current State == Complete and Functional
ButtonSaveCurrentTemplate:
FileSelectFile, toSaveFileName, S24, %A_WorkingDir%, Save Template, Template (*.ini)
toSaveFileName := StrReplace(toSaveFileName, ".ini")
Gui, submit, NoHide
IniWrite, %startingRow%, %toSaveFileName%.ini, templateValues, startingRow
IniWrite, %endingRow%, %toSaveFileName%.ini, templateValues, endingRow
IniWrite, %extraDelayValue%, %toSaveFileName%.ini, templateValues, extraDelayValue
IniWrite, %extraTabDelayValue%, %toSaveFileName%.ini, templateValues, extraTabDelayValue
IniWrite, %requestedForSomeoneElseDDL%, %toSaveFileName%.ini, templateValues, requestedForSomeoneElseDDL
IniWrite, %phoneNumber%, %toSaveFileName%.ini, templateValues, phoneNumber
IniWrite, %phoneExtension%, %toSaveFileName%.ini, templateValues, phoneExtension
IniWrite, %buildingNumber%, %toSaveFileName%.ini, templateValues, buildingNumber
IniWrite, %roomNumber%, %toSaveFileName%.ini, templateValues, roomNumber
IniWrite, %requestedForEmployeeTypeDDL%, %toSaveFileName%.ini, templateValues, requestedForEmployeeTypeDDL
IniWrite, %briefDescription%, %toSaveFileName%.ini, templateValues, briefDescription
IniWrite, % StrReplace(description, "`n",""), %toSaveFileName%.ini, templateValues, description
IniWrite, %systemName%, %toSaveFileName%.ini, templateValues, systemName
IniWrite, %assignmentGroup%, %toSaveFileName%.ini, templateValues, assignmentGroup
IniWrite, %stateDDL%, %toSaveFileName%.ini, templateValues, stateDDL
IniWrite, %assignedTo%, %toSaveFileName%.ini, templateValues, assignedTo
return
OSD(Text="OSD",Colour="Blue",Font="Times New Roman",Size="128")
{   ; Displays an On-Screen Display, a text in the middle of the screen.
Gui, 2:Font, c%Colour% s%Size%, %Font%  ; If desired, use a line like this to set a new default font for the window.
GuiControl, 2:Font, OSDControl  ; Put the above font into effect for a control.
GuiControl, 2:, OSDControl, %Text%
Gui, 2:Show, NoActivate, OSDGui ; NoActivate avoids deactivating the currently active window; add "X600 Y800" to put the text at some specific place on the screen instead of centred.
Return
}`
An error is received:
Error: Parameter #2 of InStr is invalid.
Specifically: empty string
---- C:\Temp\AHK-v2-script-converter-master\AHK-v2-script-converter-master\ConvertFuncs.ahk
1411: {
1412: ControlName := RegExReplace(Var3, "^.*\bv([\w]*)\b.*$", "$1")

▶	1414: ControlObject := InStr(ControlName, SubStr(Var2, 1, 4)) ? "ogc" ControlName : "ogc" Var2 ControlName
1415: mGuiCObject[ControlName] := ControlObject
1416: If (Var2 != "Pic" and Var2 != "Picture" and Var2 != "Text" and Var2 != "Button" and Var2 != "Link" and Var2 != "Progress" and Var2 != "GroupBox" and Var2 != "Statusbar" and Var2 != "ActiveX")
Call stack:
C:\Temp\AHK-v2-script-converter-master\AHK-v2-script-converter-master\ConvertFuncs.ahk (1414) : [InStr] ControlObject := InStr(ControlName, SubStr(Var2, 1, 4)) ? "ogc" ControlName : "ogc" Var2 ControlName
C:\Temp\AHK-v2-script-converter-master\AHK-v2-script-converter-master\ConvertFuncs.ahk (1414) : [_Gui] ControlObject := InStr(ControlName, SubStr(Var2, 1, 4)) ? "ogc" ControlName : "ogc" Var2 ControlName
C:\Temp\AHK-v2-script-converter-master\AHK-v2-script-converter-master\ConvertFuncs.ahk (749) : [Convert] Line := Indentation . FuncObj(Param)
C:\Temp\AHK-v2-script-converter-master\AHK-v2-script-converter-master\QuickConvertorV2.ahk (386) : [ButtonConvert] V2Edit.Text := Convert(V1Edit.Text)
C:\Temp\AHK-v2-script-converter-master\AHK-v2-script-converter-master\QuickConvertorV2.ahk (900) : [Sleep] Sleep(100)
C:\Temp\AHK-v2-script-converter-master\AHK-v2-script-converter-master\QuickConvertorV2.ahk (900) : [] Sleep(100)

~LButton

Sorry if the post is hard to read or formatted wrong, I'm new here.

It seems SubStr(Var2,1,4) returns an empty string, that seems to be the error.
If you can provide the correct conversion, I can try to add it to the convertor.
Please try to filter the code to a simple short version that demonstrates the error, to make it easy for us to fix the conversion.

Example minimal code:
Gui, Add, ListBox, w300 h200 hwndhOutput

The reason this was failing was because the gui line had an hwnd output, but no 4th parameter.
To access the the value v2 requires saving the control as a variable the using the .hwnd property, to create this variable name the converter based the name off of the 4th parameter, and if it wasn't defined the script then errored.
To fix this I added if 4th param is blank to base the name off of the Control type (followed by a number to avoid conflicts)
If anyone has a better way please reply

source: gharchive/issue

authors: Banaanae SunSerega ThirdRise dmtr99

license: Unlicense

license_type: permissive

license_source: github-api


text:
Last Fix On All Submissions

fix all diagrams and add more extensions
update : fixed some problems in diagrams

DONE

license: MIT


text:
How will this project compare to the other two DataGridBundles?

I know this isn't really the place to ask questions, but I'm looking for a good datagridbundle for symfony and find the two below lacking row selection:
https://github.com/APY/APYDataGridBundle
https://github.com/stwe/DatatablesBundle
Seeing that you're building yet another datagrid I'm wondering:
How does this datagridbundle differ from the other two?
And what is this project focusing on implementing?

Sorry I missed your question some months ago, but for historical sake (and in case anyone else reads this) let me try to answer.
This bundle presently handles 3 types of grids:

DataTables
jqGrid
html

It integrates well with Doctrine ORM and ODM (MongoDB) using annotations on the entity / document classes themselves.

authors: Sluimers mmucklo

repo: mmucklo/DtcGridBundle


text:
Auto refresh

Do you think there is a way you add auto refresh? This could have number of seconds in Options and do a reload in the background after that amount of time if the file has changed. Maybe a file watcher could be used if secs is zero so it triggers on the event rather than polls
Use case - shared vault - someone else updates the note I am looking at - syncthing then rejects the file change within a few secs - my note preview refreshes.

Don't mind doing a pull request and having a go myself if you can give me some thoughts/pointers

Added in https://github.com/mnaoumov/obsidian-refresh-preview/releases/tag/2.0.0

authors: andymarden mnaoumov

repo: mnaoumov/obsidian-refresh-preview


text:
BrokenProcessPool with compute_covariance on loaded epochs

Description of the problem
The cross-validation step to select the best estimator fails in joblib. Setting n_jobs=1 does by-pass the problem, but it would still be interesting to figure out what is going wrong here.
Traceback
_RemoteTraceback:
"""
Traceback (most recent call last):
  File "/home/scheltie/pyvenv/mscheltienne/mne-python/lib/python3.10/site-packages/joblib/externals/loky/process_executor.py", line 426, in _process_worker
    call_item = call_queue.get(block=True, timeout=timeout)
  File "/usr/lib/python3.10/multiprocessing/queues.py", line 122, in get
    return _ForkingPickler.loads(res)
  File "/home/scheltie/pyvenv/mscheltienne/mne-python/lib/python3.10/site-packages/joblib/numpy_pickle.py", line 600, in load_temporary_memmap
    add_maybe_unlink_finalizer(obj)
  File "/home/scheltie/pyvenv/mscheltienne/mne-python/lib/python3.10/site-packages/joblib/_memmapping_reducer.py", line 72, in add_maybe_unlink_finalizer
    "".format(type(memmap), id(memmap), os.path.basename(memmap.filename),
  File "/usr/lib/python3.10/posixpath.py", line 142, in basename
    p = os.fspath(p)
TypeError: expected str, bytes or os.PathLike object, not NoneType
"""

The above exception was the direct cause of the following exception:

Traceback (most recent call last):

  Cell In[2], line 5
    cov = compute_covariance(

  File <decorator-gen-219>:12 in compute_covariance

  File ~/git/mscheltienne/mne-python/mne/cov.py:1161 in compute_covariance
    cov_data = _compute_covariance_auto(

  File ~/git/mscheltienne/mne-python/mne/cov.py:1386 in _compute_covariance_auto
    loglik = _cross_val(data, estimator, cv, n_jobs)

  File ~/git/mscheltienne/mne-python/mne/cov.py:1419 in _cross_val
    cross_val_score(

  File ~/pyvenv/mscheltienne/mne-python/lib/python3.10/site-packages/sklearn/model_selection/_validation.py:562 in cross_val_score
    cv_results = cross_validate(

  File ~/pyvenv/mscheltienne/mne-python/lib/python3.10/site-packages/sklearn/utils/_param_validation.py:211 in wrapper
    return func(*args, **kwargs)

  File ~/pyvenv/mscheltienne/mne-python/lib/python3.10/site-packages/sklearn/model_selection/_validation.py:309 in cross_validate
    results = parallel(

  File ~/pyvenv/mscheltienne/mne-python/lib/python3.10/site-packages/sklearn/utils/parallel.py:65 in __call__
    return super().__call__(iterable_with_config)

  File ~/pyvenv/mscheltienne/mne-python/lib/python3.10/site-packages/joblib/parallel.py:1952 in __call__
    return output if self.return_generator else list(output)

  File ~/pyvenv/mscheltienne/mne-python/lib/python3.10/site-packages/joblib/parallel.py:1595 in _get_outputs
    yield from self._retrieve()

  File ~/pyvenv/mscheltienne/mne-python/lib/python3.10/site-packages/joblib/parallel.py:1699 in _retrieve
    self._raise_error_fast()

  File ~/pyvenv/mscheltienne/mne-python/lib/python3.10/site-packages/joblib/parallel.py:1734 in _raise_error_fast
    error_job.get_result(self.timeout)

  File ~/pyvenv/mscheltienne/mne-python/lib/python3.10/site-packages/joblib/parallel.py:736 in get_result
    return self._return_or_raise()

  File ~/pyvenv/mscheltienne/mne-python/lib/python3.10/site-packages/joblib/parallel.py:754 in _return_or_raise
    raise self._result

BrokenProcessPool: A task has failed to un-serialize. Please ensure that the arguments of the function are all picklable.

Steps to reproduce
from mne import compute_covariance, read_epochs

epochs = read_epochs("/home/scheltie/Downloads/short-epo.fif")
cov = compute_covariance(
    epochs,
    tmin=None,
    tmax=0,
    method="auto",  # ('shrunk', 'diagonal_fixed', 'empirical', 'factor_analysis')
    cv=3,
    n_jobs=6,
)

Interestingly, I can not reproduce with the sample dataset..
Link to data
short-epo.zip
Additional information
Fresh environment with MNE-main.
mne.sys_info()
Platform             Linux-6.4.6-76060406-generic-x86_64-with-glibc2.35
Python               3.10.12 (main, Jun 11 2023, 05:26:28) [GCC 11.4.0]
Executable           /home/scheltie/pyvenv/mscheltienne/mne-python/bin/python
CPU                  x86_64 (12 cores)
Memory               31.0 GB

Core
├☑ mne               1.6.0.dev126+gf3bb56d1d
├☑ numpy             1.26.0 (OpenBLAS 0.3.23.dev with 12 threads)
├☑ scipy             1.11.3
├☑ matplotlib        3.8.0 (backend=Qt5Agg)
├☑ pooch             1.7.0
└☑ jinja2            3.1.2

Numerical (optional)
├☑ sklearn           1.3.1
├☑ nibabel           5.1.0
├☑ nilearn           0.10.1
├☑ dipy              1.7.0
├☑ pandas            2.1.1
└☐ unavailable       numba, openmeeg, cupy

Visualization (optional)
├☑ pyvista           0.42.2 (OpenGL 4.6 (Core Profile) Mesa 23.1.3-1pop0~1689084530~22.04~0618746 via Mesa Intel(R) UHD Graphics 770 (ADL-S GT1))
├☑ pyvistaqt         0.11.0
├☑ vtk               9.2.6
├☑ qtpy              2.4.0 (PyQt5=5.15.2)
└☐ unavailable       ipympl, pyqtgraph, mne-qt-browser, ipywidgets, trame_client, trame_server, trame_vtk, trame_vuetify

Ecosystem (optional)
├☑ mne-bids          0.14.dev0
├☑ mne-connectivity  0.6.0dev0
└☐ unavailable       mne-nirs, mne-features, mne-icalabel, mne-bids-pipeline

I can replicate the problem with my current mne env but not with another
env that uses older python and mne versions.

authors: agramfort mscheltienne

repo: mne-tools/mne-python


text:
mne.grand_average for source estimates

Describe the new feature or enhancement
For consistency between sensor and source analysis, it would be nice to allow for mne.grand_average as input data a list of mne.SourceEstimate. Users might be fooled into believing that grand avering source estimates it not suggested.
Describe your proposed implementation
the all_inst parameter that takes the evoked datasets of mne.grand_average should  allow for list of mne.SourceEstimate. All source estimates in the list (https://mne.tools/stable/generated/mne.SourceEstimate.html) should have the same number of vertices. The nave parameter of the evokeds could be set to 1 as a workaround. interpolate_bads and drop_bads should check if evokeds equal Source Estimate and if True, both parameters should be set to False.
Describe possible alternatives
An alternative could be to implement a separate function for the source estimate class  [mne.SourceEstimate], that computes grand_averages on a list of source estimates.
Additional context
No response

just out of curiosity, what is the motivation for this versus doing the grand average on Evoked sensor data before applying the inverse?  Are you doing some additional processing of the STCs before averaging?

Good point, there is a note in the documentation of mne.grand_average that states: "A grand average evoked should not be used for source localization." There is no further explanation why this is a bad idea.

It probably has to do with the way we whiten the data? The thought of an average noise covariants matrix raises my internal eyebrows a bit ... but I'm just blindly guessing here! @agramfort probably knows the answer!

Right, of course, I wasn't thinking of the across-subjects case (but of course that's the main use case for grand averages). Another problem is that at the sensor level we have no guarantee of equivalent head position (and for EEG, no guarantee of equivalent sensor position even). After inverse and morphing those problems go away

authors: CarinaFo drammock hoechenberger


text:
MultiTaskLasso and GAT

@jona-sassenhagen @agramfort @dengemann
On my computer, the MultiTaskLasso from sklearn seems to be unable to run parallel predictions (fit is fine though). I haven't run an investigation yet... Do you encounter the same issue?
import numpy as np
import mne
from mne.datasets import sample
from mne.decoding import GeneralizationAcrossTime
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import make_pipeline
from sklearn.linear_model import MultiTaskLasso
from sklearn.cross_validation import KFold

# preproc
data_path = sample.data_path()
raw_fname = data_path + '/MEG/sample/sample_audvis_filt-0-40_raw.fif'
events_fname = data_path + '/MEG/sample/sample_audvis_filt-0-40_raw-eve.fif'
raw = mne.io.Raw(raw_fname, preload=True)
picks = mne.pick_types(raw.info, meg=True, exclude='bads')  # Pick MEG channels
events = mne.read_events(events_fname)
event_id = {'AudL': 1, 'AudR': 2, 'VisL': 3, 'VisR': 4}
epochs = mne.Epochs(raw, events, event_id, -0.050, 0.600, proj=True,
                    picks=picks, baseline=None, preload=True,
                    reject=dict(mag=5e-12), verbose=False)

# Fit multiple conditions at once
events_side = epochs.events[:, 2] % 2
events_modality = epochs.events[:, 2] > 2
Y = np.vstack((events_side, events_modality)).T

# GAT
clf = make_pipeline(StandardScaler(), MultiTaskLasso(alpha=.01))
gat = GeneralizationAcrossTime(clf=clf, cv=KFold(len(Y)), n_jobs=-1)
gat.fit(epochs, y=Y)
gat.predict(epochs)  # seems to run a single core, and thus takes for ever

Works fine in parallel for me.

gat.predict(epochs)  # seems to run a single core, and thus takes for ever
[Parallel(n_jobs=48)]: Done   1 out of   1 | elapsed:  1.2min remaining:    0.0s
[Parallel(n_jobs=48)]: Done   1 out of   1 | elapsed:  1.2min finished

no idea

I updated to sklearn v.17 and it works now.
Thanks!

Arg, updating it through conda made the problem reappear.. And removing or reinstalling sklearn through pip doesn't change anything anymore. I'll re-open it until I find the fix.

https://github.com/mne-tools/mne-python/pull/2856 fixes it. I suspect this is the list of list repr and/or the nested lists concatenation that caused the issue. No problem with np.arrays anymore.

authors: agramfort jona-sassenhagen kingjr


text:
Annotations to_data_frame with all the options similar to Raw.to_data_frame

Describe the new feature or enhancement
Annotations has a convenience function to go to a data frame, and so does Raw. However, Raw has significantly more flexibility and options.
Now that Annotations also has channel picks, almost all the options that Raw.to_data_frame has can be also added to Annotations.
Describe your proposed implementation
Implement Annotations.to_data_frame() with parameters of Raw.to_data_frame().
Additional comments
See current Raw.to_data_frame(): https://mne.tools/stable/generated/mne.io.Raw.html#mne.io.Raw

why not

I've been doing a lot of Annotations fancy handling for derived datasets from Raw recently and it's always nice having MNE eat that complexity :p


text:
[BUG] Fix plot_topomap with sphere="eeglab"

I remember seeing that it was now possible to set sphere="eeglab" but it requires that an Info gets provided to _check_sphere.
Failing on main, fixed here:
import mne

raw_fname = mne.datasets.eegbci.load_data(subject=6, runs=(1,))[0]
raw = mne.io.read_raw(raw_fname, preload=True, verbose=False)
mne.datasets.eegbci.standardize(raw)  # set channel names
raw.set_montage("standard_1005", verbose=False)

bridged_idx, ed_matrix = mne.preprocessing.compute_bridged_electrodes(raw)

mne.viz.plot_bridged_electrodes(
    raw.info,
    bridged_idx,
    ed_matrix,
    topomap_args=dict(vmax=5, sphere="eeglab")
)

The test I added is a bit indirect, but it was simpler 😅

LGTM, thanks in advance @mscheltienne !

source: gharchive/pull-request

authors: larsoner mscheltienne


text:
adding numpy integer check

I noticed that in python 3 sometimes pick_channels will cause code to break, because it seems like numpy numeric types behave slightly differently. If you do isinstance(np.int64(3), int) it'll return False in python3, which caused some functions to error. This is just one example that I was currently trying to run, but it seems like we might need to find other places in the code where similar things are happening, and add a np.integer check as well?

To clarify: the problem is that the pick_channels function will return an array of numpy ints, so when you passed that array to the plot_comparison_evokeds function, it'd return an error because the elements in the array are of type np.integer, instead of int

That's a case for mne.externals.six.integer_types right?

hmm, I just tried that but it didn't work. For me integer_types just
returns (int,)
On Wed, Oct 12, 2016 at 4:08 PM jona-sassenhagen notifications@github.com
wrote:

That's a case for mne.externals.six.integer_types right?
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
https://github.com/mne-tools/mne-python/pull/3660#issuecomment-253365631,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ABwSHbNX7j34ZTRMjemYT5Xo2dIGhtvGks5qzWh_gaJpZM4KVTKE
.

Current coverage is 87.39% (diff: 100%)

Merging #3660 into master will not change coverage

@@             master      #3660   diff @@
==========================================
  Files           343        343
  Lines         60765      60765
  Methods           0          0
  Messages          0          0
  Branches       9300       9300
==========================================
  Hits          53108      53108
  Misses         4903       4903
  Partials       2754       2754

Powered by Codecov. Last update 65adad7...7804fee

can you check if isinstance(np.int(3), int) is True for you?
it which case we should understand why we don't have np.int from pick
function and eventually fix it. I feel you fix it at the wrong place as
it's likely to hit the same bug elsewhere

Yes, that does return True. I remember coming across some article that said numpy handles the intXX types differently. However it seems like numpy defaults to using those versions instead of np.int. E.g.:
isinstance(np.arange(10)[0], int)
returns False as well...

that's really weird
no objection to merge then
@Eric89GXL ok for you?

Yeah. We might need to tackle this more systematically at some point but I'm fine with an incremental improvement/fix in the meantime.

please merge then

Thanks @choldgraf

I'll ask the numpy folks here at BIDS about what they recommend
On Thu, Oct 13, 2016, 11:21 AM Eric Larson notifications@github.com wrote:

Thanks @choldgraf https://github.com/choldgraf
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/mne-tools/mne-python/pull/3660#issuecomment-253595777,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ABwSHTF_8lX2NedpXIDddOfq91UaiLU5ks5qznaggaJpZM4KVTKE
.

it looks like in sklearn there are some spots that just use the variable FLOAT_TYPES or INTEGER_TYPES which are just collections of types (e.g. (np.int32, np.int64, int)).

authors: Eric89GXL agramfort choldgraf codecov-io jona-sassenhagen


text:
[WIP] Deprecate EDF

Things that need to happen:

[x] load edf files with annotations, and find events
[x] new deprecation messages
[x] remove 'EDF Annotations' channel

Nice to have:

[ ] preload=false, loads the annotations but not the data.

@alexandrebarachant may have done this for
https://github.com/NeuroTechX/moabb
can we check if we broke anything there? @alexandrebarachant do you have a
minute to test?

yes, I broke it. I'm fixing it. But if more people can test (and share) that would be awesome!

There would be a subsequent PR improving the test suit etc.. tests would be able to be added.

@larsoner can you take a look at this one?

Ok. First of all, thanks a lot for the examples they bring light to some shady things. (+ I really loved the BDF. I think we should have the same file for all the formats we have)
Here follows, some tests and thougts.
EDF
Here we compare if master and the PR read the same things or not
def test_edf_compare_sotred_annotations_when_reading(recwarn):
    from mne.io.pick import channel_indices_by_type
    from mne import find_events

    raw = read_raw_edf(edf, preload=True)
    annot = read_annotations(edf)
    found_types = [k for k, v in
                   channel_indices_by_type(raw.info, picks=None).items()
                   if v]
    events = find_events(raw, shortest_event=1)

    print(f'\n Annotations load in read_raw_edf: {raw.annotations}')
    print(f'The read types are {found_types}')
    print(f'Annotations in the file {annot}')
    print(f'Having {events.shape[0]} evnts for {raw.get_data().shape[1]}'
          f' samples is a ratio of {events.shape[0]/raw.get_data().shape[1]}')

For master:
Annotations load in read_raw_edf: <Annotations  |  41 segments : a1+a2 (1), aanspreken (1), ademh (1)..., orig_time : 2005-09-15 10:18:42>
The read types are ['eeg', 'stim']
Annotations in the file <Annotations  |  41 segments : a1+a2 (1), aanspreken (1), ademh (1)..., orig_time : None>
Having 39 evnts for 363620 samples is a ratio of 0.00010725482646719103

For the PR case:
Annotations load in read_raw_edf: <Annotations  |  20 segments : a1+a2 (1), aanspreken (1), ademh (1)..., orig_time : 2005-09-15 10:18:42>
The read types are ['eeg', 'stim']
Annotations in the file <Annotations  |  41 segments : a1+a2 (1), aanspreken (1), ademh (1)..., orig_time : None>
Having 270100 evnts for 363620 samples is a ratio of 0.7428084263791871

I broke something. My guess is that the stim channel and the annotations represent the same data (39~=41) but something is really broken in the PR.
Plus, from the 41 annotations in the EDF file, 21 get kicked out 'cos they are out of the span of the raw object.
def test_edf_times(recwarn):
    raw = read_raw_edf(edf, preload=True)
    annot = read_annotations(edf)

    # Print annotation boundaries
    for name, a in [('raw.annotations', raw.annotations),
                    ('annot', annot)]:
        print(f'\nin {name} onsets go from {min(a.onset)}s to {max(a.onset)}s')
        print(f'which {max(a.onset)} < {raw.times[-1]}'
              f' is evaluated to {max(a.onset)<raw.times[-1]}')

For master:
in raw.annotations onsets go from 0.0s to 1800.0s
which 1800.0 < 1818.095 is evaluated to True

in annot onsets go from 0.0s to 1800.0s
which 1800.0 < 1818.095 is evaluated to True

For the PR case:
in raw.annotations onsets go from 0.0s to 1450.0s
which 1450.0 < 1454.476 is evaluated to True

in annot onsets go from 0.0s to 1800.0s
which 1800.0 < 1454.476 is evaluated to False

This suggest that there's something fishy, not with the annotations but in the reading of the sfreq.
BDF
Well, here is clear that 'BDF Annotations' is not picked as stim.
def test_plot_bdf_master(recwarn):
    from mne.io.pick import channel_indices_by_type
    from mne import find_events
    raw = read_raw_edf(bdf)
    # XXX: There's no read_annotations for bdf (only edf)
    # annot = read_annotations(bdf)
    found_types = [k for k, v in
                   channel_indices_by_type(raw.info, picks=None).items()
                   if v]
    # XXX: find_events with no stim channel would break in this PR
    # events = find_events(raw, shortest_event=1)

    print(f'\n Annotations load in read_raw_edf: {raw.annotations}')
    print(f'The read types are {found_types}')
    print(f'The shape of the data is {raw.get_data().shape}')
    print(f"Channel names in _raw_extras: {raw._raw_extras[0]['ch_names']}")

    my_scaling = {k: 'auto' for k in found_types}
    raw.plot(scalings=my_scaling)

in master:
Annotations load in read_raw_edf: <Annotations  |  0 segments , orig_time : None>
The read types are ['eeg', 'stim']
The shape of the data is (12, 120000)
Channel names in _raw_extras: ['squarewave', 'ramp', 'pulse', 'ECG', 'noise', 'sine 1 Hz', 'sine 8 Hz', 'sine 8.5 Hz', 'sine 15 Hz', 'sine 17 Hz', 'sine 50 Hz', 'STI 014']

in PR:
Annotations load in read_raw_edf: <Annotations  |  0 segments , orig_time : None>
The read types are ['eeg']
The shape of the data is (12, 120000)
Channel names in _raw_extras: ['squarewave', 'ramp', 'pulse', 'ECG', 'noise', 'sine 1 Hz', 'sine 8 Hz', 'sine 8.5 Hz', 'sine 15 Hz', 'sine 17 Hz', 'sine 50 Hz', 'BDF Annotations']

So it does not realize that 'BDF Annotations' is a tal_ch despite the fact
that it does for our BDF file in the testing. Which it should 'cos the rule is that
it picks the last channel in edf_info (then
stored in raw._raw_extras) as the annotation channel.
It does not get picked up as a stim, and added to annotations (or stim) is just treated as eeg.

To sum up, I'm taking a look at all this.

I think this is driving me crazy. 'BDF Annotations' in the example does not seem to follow the same annotations pattern.

By looking at the BDF example (there's also an edf example with the same data), we should recover the following channels (+ two annotations: start, stop)
signal label/waveform  amplitude    f       sf
---------------------------------------------------
   1    squarewave        100 uV    0.1Hz   200 Hz
   2    ramp              100 uV    1 Hz    200 Hz
   3    pulse             100 uV    1 Hz    200 Hz
   4    ECG               100 uV    1 Hz    200 Hz
   5    noise             100 uV    - Hz    200 Hz
   6    sine 1 Hz         100 uV    1 Hz    200 Hz
   7    sine 8 Hz         100 uV    8 Hz    200 Hz
   8    sine 8.5 Hz       100 uV    8.5Hz   200 Hz
   9    sine 15 Hz        100 uV   15 Hz    200 Hz
  10    sine 17 Hz        100 uV   17 Hz    200 Hz
  11    sine 50 Hz        100 uV   50 Hz    200 Hz

And this is what we get based on the following:
@pytest.mark.parametrize('fname', [test_generator_bdf, test_generator_edf])
def test_load_toy_examples_in_edf_branch(fname, recwarn):
    from mne.io.pick import channel_indices_by_type

    print(f'\n------------ fname: {fname} ---------')
    raw = read_raw_edf(test_generator_bdf)
    found_types = [k for k, v in
                   channel_indices_by_type(raw.info, picks=None).items()
                   if v]
    events, event_id = events_from_annotations(raw)
    print(f'The read types are {found_types}')
    print(f'The shape of the data is {raw.get_data().shape}')
    print(f"Channel names in _raw_extras: {raw._raw_extras[0]['ch_names']}")
    print(f'Annotations load in read_raw_edf: {raw.annotations}')
    print(f'Event ids found in Annotations: {event_id}')
    print(f'Events loaded:\n {events}')

    # raw.plot(scalings={k:'auto' for k in found_types},
    #          title=op.basename(fname))

------------ fname: /home/sik/code/mne-python/mne/io/edf/tests/data/test_generator_2.bdf ---------
The read types are ['eeg', 'stim']
The shape of the data is (12, 120000)
Channel names in _raw_extras: ['squarewave', 'ramp', 'pulse', 'ECG', 'noise', 'sine 1 Hz', 'sine 8 Hz', 'sine 8.5 Hz', 'sine 15 Hz', 'sine 17 Hz', 'sine 50 Hz', 'BDF Annotations']
Annotations load in read_raw_edf: <Annotations  |  2 segments : rec (2), record (1), orig_time : 2009-12-10 12:45:54>
Event ids found in Annotations: {'RECORD START': 1, 'REC STOP': 2}
Events loaded:
 [[     0      0      1]
 [120000      0      2]]

------------ fname: /home/sik/code/mne-python/mne/io/edf/tests/data/test_generator_2.edf ---------
The read types are ['eeg', 'stim']
The shape of the data is (12, 120000)
Channel names in _raw_extras: ['squarewave', 'ramp', 'pulse', 'ECG', 'noise', 'sine 1 Hz', 'sine 8 Hz', 'sine 8.5 Hz', 'sine 15 Hz', 'sine 17 Hz', 'sine 50 Hz', 'BDF Annotations']
Annotations load in read_raw_edf: <Annotations  |  2 segments : rec (2), record (1), orig_time : 2009-12-10 12:45:54>
Event ids found in Annotations: {'RECORD START': 1, 'REC STOP': 2}
Events loaded:
 [[     0      0      1]
 [120000      0      2]]

Essentially we recover what we should recover: 11 channels + 2 annotations. But we have this stim channel, that is properly recoverd in master (see https://github.com/mne-tools/mne-python/pull/5741#issuecomment-442879751) but that I cannot find where is the data within the file, and that gets further filtered wrongly despite being tag as 'stim'.

There are only 11 normal channels in both the EDF and BDF files. What gets added as a 12th channel are the two annotations - MNE synthesizes a new channel for that. I'd say we shouldn't do this, because the annotations are already in raw.annotations.

@cbrnr we should not synthesize a stim channel. Agreed.
But here's what is puzzling me, the only annotations in the tal channel should be these two annotations that we find: (start, and stop). However there is more stuff somewhere. Because the data we recover in STI 014 is completely plausible.

You're right, this happens in the case of the BDF file but not the EDF file. I have no idea where the data comes from - I tried opening the BDF in SigViewer, which shows 11 channels and 2 annotations...

when you say 11+2 you mean:
a) 11 channels + 2 annotations as ('RECORD START', and 'REC STOP')
or b) 11 channels + 2 types of annotations (one containing start/stop, and another type contaning a 31 onsets)
To me the most logical is b. I've been parsing the file by hand.
Then the question would be when to parse it and how to determine what belongs to who.

Ok, now the plot seems better

But there are still things I don't understand. The picks seem reasonable (they are sync with the ECG) artifacts. But whatever is in that channel does not comply with the TAL format. (or at least with the regex that we use).
What I don't understand is why it gets picked up properly. It makes no sense, 'cos unless there's magic happening in many_chunk = _read_ch(fid, subtype, ch_offsets[-1] * n_read, dtype_byte, dtype).reshape(n_read, -1) it should not work. 'cos it reads as a buffer of triplets of np.uint8 something of the shape (onset, duration, description). And we know for a fact that this is there 'cos we recover the 2 annotations. That actually follow this format.
If the encoding of the 2 annotations were to be the 51 and 34 samples encoded in the header (51 for bdf and 34 for edf) the impulses in the stim channel would end up in random places not sync with ECG. (+ it would be the same amount of samples for both files)
What I do find plausible is that the burst that we see in both files at the beginning of the stim channel are the miss interpretation of this bytes:
�\0\0+0\0+0.0000RECORD START\0\0\0\0\0\0\0\0\0
...
���6�W�w����������<�]�}�������\0\0 \0A\0b\0�\0�\0�\0�\0&Gh����-Mn����3St����9Zz����?`����$Ef����
*Kl����1Qr����	7	X	x	�	�	�	�
=
^
~
�
...
\04�\0\0�\0\04�\0\0�\0\04�\0\0�\0\04�\0\0�\0\04�\0\0�\0\04�\0\0�\0\04�\0\0�\0\04�\0\0�\0\04�\0\0�\0\04�\0\0�\0\04�\0\0�\0\04�\0\0�\0\04�\0\0+1\0+600.0000REC STOP

No, I meant (a), 11 channels plus 2 annotations. The last channel is definitely not in the file, it seems to get created by samples that belong to the ECG channel. I've checked the header with a hex editor, there are only 11 channels plus the "EDF Annotations" channel (which contains 2 annotations).

Rebasing master to avoid some timeouts in travis

merged and release of testing data done:
https://github.com/mne-tools/mne-testing-data/releases/tag/0.61

pushed a cosmit. One more thing. We still have mne.io.edf.find_edf_events and the find_edf_events method for RawEDF but I don't think there is anymore test. If we remove the tests in this PR we should deprecate too.
thx @massich

ok
so you both want to merge this even though there is no test anymore for
find_edf_events?
I can accept this :)

@larsoner, @cbrnr can any of you give it a last look and merge if you are happy?

I already commented a few minutes ago

Thanks @massich !

authors: agramfort cbrnr larsoner massich


text:
MRG: Change way NIRS frequency is encoded

Reference issue
Addresses issue #7057
What does this implement/fix?
Change the way NIRS light frequency is encoded as suggested by @larsoner

thx @rob-luke

authors: agramfort rob-luke


text:
WIP: Add support for reading and writing sufaces to .obj

Add support to exporting FreeSurfer surfaces to .obj files so you can import them in blender.

See also: https://github.com/ezemikulan/blender_freesurfer
Todo:

[x] Implement writing .obj files
[x] Implement reading .obj files
[x] Basic unit tests
[ ] Finish unit tests for full coverage
[ ] Add tutorial on how to use this to fix Surface inner skull is not completely inside surface outer skull errors
[ ] Update what's new

Alternatively, is there a good way to run a single test inside a Jupyter console? (I usually need the postmortem debugger)

Personally I just do:
pytest mne/tests/test_whatever.py -k test_something --tb=short --pdb

this drops to a (pdb) prompt where you can even do interactive and then have a standard python terminal (with matplotlib interactive, etc.). Not sure if there is a way to get this to be an ipython rather than python terminal, maybe with something like https://cprohm.de/article/ipytest-running-pytest-in-ipython-notebooks.html/ ?

Sphinx-gallery gallery_conf["plot_gallery"] was False, so no examples were executed.
Does that mean that CircleCI is complaining that no examples needed to be build or something?

No, it's a warning about optipng (warnings are treated as errors) that you can safely ignore. It's because your branch is out of date and CircleCI doesn't / can't merge the yaml before executing

I'm still working on the "fix my BEM with Blender" tutorial, which I feel should be part of this PR.

Can anyone help me getting the static images (blender screenshots) properly embedded the the tutorial text?

I can push a commit to fix the warnings and add a thumbnail (hopefully)

(FYI testing locally with PATTERN=in_blender make html_dev-pattern allows for fairly quick iteration to fix bugs)
Grr... something is wrong with the SG static thumb embedding. I'll probably need to fix that at the SG end, but the syntax here is correct so shouldn't be a blocker for merge

... turns out I just can't spell

When CI comes back green, this is ready to merge from my end.

Green other than timeouts that are not your fault that we can ignore

The files are actually kind of big (500 / 700 kB), maybe some suitable JPG compression could be used?

Image filesizes are around 100kb now

looks good https://20582-1301584-gh.circle-artifacts.com/0/dev/auto_tutorials/source-modeling/plot_fix_bem_in_blender.html#sphx-glr-auto-tutorials-source-modeling-plot-fix-bem-in-blender-py

CI's were timing out

Hi, sorry for the late reply, looks great to me!

Hi @ezemikulan, thanks! If you can state you full name I can add you properly instead of just your username.

It is Ezequiel Mikulan
Thanks again

authors: agramfort ezemikulan larsoner wmvanvliet


text:
Fix TOC toggle button in Report

What does this implement/fix?
The button, which is supposed to toggle the TOC, actually toggled the navbar…
master

PR branch

@jasmainak maybe it was done on purpose when you have too many blue
buttons/sections?

Oh. That could make sense… however we'd have to rethink the implementation then :)

yes the navbar toggling is on purpose
@dengemann had a usecase for it where he had navbars spanning multiple lines with 50-100 subjects (=50-100 sections)

Ok, so then it's a UI design issue for me… will do some thinking and propose a solution. Closing for now. Thanks for your feedback!

authors: agramfort hoechenberger jasmainak


text:
ENH: code to handle QR special text

I believe this project may benefit from handling QR special text, as commonly accepted by other QR implementation, e.g. ZXing.
This code should correctly handle: QrPhone, QrEmail, QrMessage, QrGeolocation, QrUrl, QrContact (MeCard), QrWifi.
It is meant to run unmodified on both Python2 and Python3 identically.
I have copy-pasted some code that I have written for myself, so apologies if the docstrings may not comply to what you usually use. Feel free to modify to fit your project better.
I have also adapted the copyright notice to comply with yours.

Thanks for spotting that, it should be fixed now :-)

I actually believe it shoul be modified again, as url should be the first argument of the constructor

Done.

license_source: bigquery


text:
Fe 3: As a user, I want to upload and preview PDFs

Could do better on unit tests, will update with later functionality
Added Majestic for unit testing
Updated UI designs and followed those
Uses an alert to display an error, may change in the future for accessibility reasons

:00000 idk why it says I have all these merge conflicts. I fixed them all and then it didn't save my changes >::(((((. I think git hub hates me.

I feel like I did something stupid but who knows

im stupid i never created a new branch


text:
Version 1.4.3 is broken

Version 1.4.3 gives the following error.
Cannot find module '../dist/index'
Version 1.4.2 works fine with
npx unity-changeset@1.4.2 list

@aurelien-lbc
Thank you for your reporting!
The release workflow was broken.
Now, v1.4.5 works correctly! 😄

authors: aurelien-lbc mob-sakai

repo: mob-sakai/unity-changeset


text:
Fix fee calc bug caused by 0 bal transactions in unspent list

In this PR

Defrag integration test was unexpectedly failing with insufficient funds
Funds were available - so test should not have failed
Inspection revealed the 0-bal transactions inflating the defrag fee cost
Proposed fix here is to filter out 0-bal transactions from unspent txos
Alternate fix could be to leave the 0-bal transactions  in the list, and update fee calc logic to exclude

fixes #184740756

Purpose of PR was to enable discussion around the topic - will revisit this shortly with a final actual solution after further investigation

repo: mobilecoinofficial/MobileCoin-Swift


text:
🛑 RequetePizza Web is down

In 7c8ba19, RequetePizza Web (https://requetepizza.com) was down:

HTTP code: 0
Response time: 0 ms

Resolved: RequetePizza Web is back up in d014bd0 after 563 days, 19 hours, 42 minutes.

repo: mobilitysol/monitorweb


text:
Firebase reading

Hi. I am designing a system that must have two-way communication with firebase. It is very simple to write to my database, but it is not practical for me to make periodic readings to obtain the stored data. By doing this, I eventually get an error, or worse, my system resets. Is there a way to know if the database has been modified, so that I can read it, or a way to monitor a value in real time? I am using a Wemos D1 mini. Thank you very much.

This example and this are what you're looking for.
Please read through the README for how to use that feature.

authors: jorgele mobizt


text:
datakit: use Irmin.Merge.idempotent instead of re-implementing our own

Signed-off-by: Thomas Gazagnaire thomas@gazagnaire.org

Seems that CircleCI's VM is broken, merging anyway as the rest is green.

repo: moby/datakit


text:
ocaml: update dependencies and harden the notification loop

update to opam package manager version 2
refresh all the dependencies

There is some evidence that the notification loop is spinning, due to an Lwt_unix.read call returning -1: https://github.com/docker/for-mac/issues/3499#issuecomment-623960890 . This is not supposed to happen but perhaps it is possible if the fd is set to the wrong blocking mode, such that -1, EAGAIN are returned but not handled correctly.
This PR

ensures the non-blocking mode is set correctly
logs and exits if the call returns <0, which will highlight the problem and prevent spinning

@samoht WDYT of this, in particular https://github.com/moby/hyperkit/pull/286/commits/6414a3c33383c011044ba1df8f6fd4965a52118b and https://github.com/moby/hyperkit/pull/286/commits/e88ddf6badb17c44b357630b5d6511e3511843c1 ?

LGTM

repo: moby/hyperkit


text:
fix test files not using .spec suffix

PR for #2383

changes all test files from test/**/*.js to test/**/*.spec.js
changes filenames with dot to use - instead (http.meta.2.js -> http-meta-2.spec.js)

Open questions:

Should i also go ahead and change the fixtures filename to use .fixture.js?
Should https://github.com/mochajs/mocha/blob/master/test/compiler/foo.js also get a .spec suffix?
Is it ok that the commit includes the generated mocha.js file?

I rebased onto current master and renamed the fixture files. The generated mocha file was also removed from the commit.

@makepanic Missed a few fixtures, but I've added those and merged this.  Thanks again; killer work!

authors: boneskull makepanic

repo: mochajs/mocha


text:
Add LenientStubber

Thank you for submitting a pull request! But first:

[x] Can you back your code up with tests?
[x] Keep your commits clean: squash your commits if necessary.

@TimvdLippe Actually... I created a PR because I needed it, but it seems to be related to #325 as well.

repo: mockito/mockito-kotlin

license: mit


text:
Set Unit of measurement for selected device classes

Some device_classes have a limited set of Unit of measurement.
If the user selects such a device class, the Unit of measurement field will be changed to select field and show only allowed value.
The first value in the list will be preselected.

Today i tried to switch from HA internal modbus integration to modbus@mqtt for Eastron SDM120-M device.
Public specification dosen't define unit of measurment for total active energy so i tried to set it. After setting state class for one entity all of them lost theirs name for couple of seconds. Next names came back and device class, UOM, ans state class dissapears. Its not possible to set state class for me.

My experience with Unit of measurement are similar. I found out, that it's a good idea to set the device class first.
UOM is not always required. Sometimes the UOM won't. be recognized by Home Assistant.
One of the next updates of modbus2mqtt will set the list of allowed unit of measurements depending on the device class.
A few device classes have a restricted set of unit of measurements.
However, this won't solve your issue.
In general, I assume this is more a home assistant issue with MQTT Discovery.
Modbus2mqtt just sends device_class and unit_of_measurement to Home Assistant.
There is no own logic.
That's why I will close this issue.
This disappearing of the name is a new issue. I saw it already, but it should have no impact on the functionality.
Once I found out the reason, I will fix it. If you want to follow this up, please create a new issue.

This is general problem with specification editor. Now i have separate HA with modbus@mqtt only (without mqtt).
When i set state class and click save fields "device class", "UOM", "state class" are cleared.
Here i example of api/modbus/specification request when i set only "device class", "UOM":

And here when i set all 3 fields:

BTW: i spent some time today to try setup project localy without luck so far :( Would be nice to see some instructions on this like you mention in documentation.

Thank you for the analysis.
You are right. This will be fixed with the next version.
Documentation standalone:
There is already issue #25 which deals with standalone installation.
Currently, I am busy with fixing and improving the app, so this must still wait a bit.

authors: arturmietek modbus2mqtt volkmarnissen


text:
Add a kani::filter_any function to enable easy generation of constrained symbolic values

Description of changes:
Currently, users must first create a value using kani::any, then constain it using kani::assume.  This is unergonomic.
Resolved issues:
Resolves #ISSUE-NUMBER
Related RFC:

Optional #ISSUE-NUMBER.
Call-outs:
Feel free to bikeshed the name

Testing:

How is this change tested? New unit test

Is this a refactor change? No

Checklist

[ ] Each commit message has a non-empty body, explaining why the change was made
[ ] Methods or procedures are documented
[ ] Regression or unit tests are included, or existing tests cover the modified code
[ ] My PR is restricted to a single feature or bugfix

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses.

Thanks! Are the updates to the s2n-quic submodule intentional?

Thanks! Are the updates to the s2n-quic submodule intentional?

No, removed them

Here's my bikeshedding 😄: kani::any_with or kani::any_such_that.

THIS. I'd prefer kani::any_with over kani::any_such_that because it's shorter and avoids mathematical jargon.

Thirding the bikeshedding over the name filter_any doesn't seem right to me. I like any_with
proptest has an any_with, but it works differently: it allows supplying arguments to the generator/strategy being used. In practice, it seems like these are often constraints: e.g. size for a vector. So I think it fits in the spirit here: we don't need/have a generator, and so we can just supply arbitrary constraints directly. So I count this as precedent for this choice of name.

I like any_where as well, but agree it's a bit funny.
crux-mir uses symbolic_where: https://github.com/GaloisInc/crucible/blob/79428012dae4e3c922f75c6f41f418c8aacca665/crux-mir/lib/crucible/symbolic.rs#L8

Yet another option: any_value_where.

We need to pick one and move on.
@danielsn please advise.

I like @zhassan-aws's suggestion of any_value_where

authors: adpaco-aws danielsn rahulku tedinski zhassan-aws

repo: model-checking/kani


text:
Support for OPCUA client

Hello,
Would you be interested to have an OPCUA client being contributed to this lib ?

This would be very interesting, but there might be some potential conflict of interests due to OPCUA library by DLR (being closed source and not part of M_DD): https://ecp.ep.liu.se/index.php/modelica/article/view/197/157

Well, we have been thinking of making the DLR OPC UA library open source, but there is no final decision, yet. It would be a distinct library (not integrated into M_DD), because the library is quite complex in itself (client and server functionality, including things like (Modelica) code generation from NodeSet2 files). I've been working on a new and more generic approach and API which finally should replace the API described in the paper. This new code already works for internal projects, but it's not complete and polished, so the library is not in a good state for releasing it right now without finishing the started stuff and cleaning up the legacy code.
Are you aware that there exists already a Modelica OPCUA-client library from Wolfram? (I think they have made it open source now, but haven't tried it, yet.)
Of course, I would be interested hearing about your ideas, the intended API, the feature set and the approach of realizing it. However, as @tbeu hinted, I'm doing work in that area and it is not open source (yet).

The wolfram library is not open source,
I have done a minimalist library based on open654 to interact with OPCUA

Yep, our library is also based on open62541. The OPC UA standard is extensive and from that perspective I think it makes more sense to have it as its own (Modelica) library instead of maintaining it as part of M_DD. Would be interesting to join efforts for such a library, but since our library is not (yet) an open-source library, it's unfortunately not possible (yet). I'll try to remember mentioning it here if there is a decision about the licensing of our internal library, but I don't expect that we will discuss this internally before June (because completing the revision and cleaning up the library will still take some time).

authors: TeoGoddet bernhard-thiele tbeu


text:
New release v1.7.0 for MSL 3.2.3

Make a new release tested/updated for MSL 3.2.3 including the features and bugfixes described in https://github.com/modelica/Modelica_DeviceDrivers/milestone/6?closed=1

Using code tag for markup 5f6935f4bac74d1eca67333674484842d76b58ce

Introduce versionBuild annotation 3d688dd68bff3063573a89d856927af6cee5742d
Rationale: Use number to distinguish draft releases that have been delivered to tool vendors for internal testing

Published MDD v1.7.0


text:
None of the inputs have requires_grad=True. Gradients will be None

Describe the bug
What the bug is, and how to reproduce, better with screenshots(描述bug以及复现过程，最好有截图)
在训练yi-vl模型和Phi-3-vision-128k-instruct模型在webui页面训练的时候报错

下面的这段是报错信息Detected kernel version 5.4.0, which is below the recommended minimum of 5.5.0; this can cause the process to hang. It is recommended to upgrade the kernel to the minimum version or higher.
[INFO:swift] The SftArguments will be saved in: /root/autodl-tmp/result-phi/phi3-vision-128k-instruct/v8-20240530-164513/sft_args.json
[INFO:swift] The Seq2SeqTrainingArguments will be saved in: /root/autodl-tmp/result-phi/phi3-vision-128k-instruct/v8-20240530-164513/training_args.json
[INFO:swift] The logging file will be saved in: /root/autodl-tmp/result-phi/phi3-vision-128k-instruct/v8-20240530-164513/logging.jsonl
Train:   0%|                                                                                | 0/100 [00:00<?, ?it/s]/root/miniconda3/lib/python3.8/site-packages/torch/utils/checkpoint.py:31: UserWarning: None of the inputs have requires_grad=True. Gradients will be None
warnings.warn("None of the inputs have requires_grad=True. Gradients will be None")
/root/miniconda3/lib/python3.8/site-packages/torch/utils/checkpoint.py:31: UserWarning: None of the inputs have requires_grad=True. Gradients will be None
warnings.warn("None of the inputs have requires_grad=True. Gradients will be None")
/root/miniconda3/lib/python3.8/site-packages/torch/utils/checkpoint.py:31: UserWarning: None of the inputs have requires_grad=True. Gradients will be None
warnings.warn("None of the inputs have requires_grad=True. Gradients will be None")
/root/miniconda3/lib/python3.8/site-packages/torch/utils/checkpoint.py:31: UserWarning: None of the inputs have requires_grad=True. Gradients will be None
warnings.warn("None of the inputs have requires_grad=True. Gradients will be None")
Traceback (most recent call last):
File "/root/autodl-tmp/swift/swift/cli/sft.py", line 5, in
sft_main()
File "/root/autodl-tmp/swift/swift/utils/run_utils.py", line 27, in x_main
result = llm_x(args, **kwargs)
File "/root/autodl-tmp/swift/swift/llm/sft.py", line 298, in llm_sft
trainer.train(training_args.resume_from_checkpoint)
File "/root/autodl-tmp/swift/swift/trainers/trainers.py", line 50, in train
res = super().train(*args, **kwargs)
File "/root/miniconda3/lib/python3.8/site-packages/transformers/trainer.py", line 1859, in train
return inner_training_loop(
File "/root/miniconda3/lib/python3.8/site-packages/transformers/trainer.py", line 2203, in _inner_training_loop
tr_loss_step = self.training_step(model, inputs)
File "/root/miniconda3/lib/python3.8/site-packages/transformers/trainer.py", line 3147, in training_step
self.accelerator.backward(loss)
File "/root/miniconda3/lib/python3.8/site-packages/accelerate/accelerator.py", line 2125, in backward
loss.backward(**kwargs)
File "/root/miniconda3/lib/python3.8/site-packages/torch/_tensor.py", line 487, in backward
torch.autograd.backward(
File "/root/miniconda3/lib/python3.8/site-packages/torch/autograd/init.py", line 200, in backward
Variable._execution_engine.run_backward(  # Calls into the C++ engine to run the backward pass
RuntimeError: element 0 of tensors does not require grad and does not have a grad_fn
Train:   0%|                                                                                | 0/100 [00:12<?, ?it/s]
Traceback (most recent call last):
File "/root/autodl-tmp/swift/swift/cli/sft.py", line 5, in
sft_main()
File "/root/autodl-tmp/swift/swift/utils/run_utils.py", line 27, in x_main
result = llm_x(args, **kwargs)
File "/root/autodl-tmp/swift/swift/llm/sft.py", line 298, in llm_sft
trainer.train(training_args.resume_from_checkpoint)
File "/root/autodl-tmp/swift/swift/trainers/trainers.py", line 50, in train
res = super().train(*args, **kwargs)
File "/root/miniconda3/lib/python3.8/site-packages/transformers/trainer.py", line 1859, in train
return inner_training_loop(
File "/root/miniconda3/lib/python3.8/site-packages/transformers/trainer.py", line 2203, in _inner_training_loop
tr_loss_step = self.training_step(model, inputs)
File "/root/miniconda3/lib/python3.8/site-packages/transformers/trainer.py", line 3147, in training_step
self.accelerator.backward(loss)
File "/root/miniconda3/lib/python3.8/site-packages/accelerate/accelerator.py", line 2125, in backward
loss.backward(**kwargs)
File "/root/miniconda3/lib/python3.8/site-packages/torch/_tensor.py", line 487, in backward
torch.autograd.backward(
File "/root/miniconda3/lib/python3.8/site-packages/torch/autograd/init.py", line 200, in backward
Variable._execution_engine.run_backward(  # Calls into the C++ engine to run the backward pass
RuntimeError: element 0 of tensors does not require grad and does not have a grad_fn
WARNING:torch.distributed.elastic.multiprocessing.api:Sending process 26530 closing signal SIGTERM
ERROR:torch.distributed.elastic.multiprocessing.api:failed (exitcode: 1) local_rank: 0 (pid: 26529) of binary: /root/miniconda3/bin/python
Traceback (most recent call last):
File "/root/miniconda3/bin/torchrun", line 8, in
sys.exit(main())
File "/root/miniconda3/lib/python3.8/site-packages/torch/distributed/elastic/multiprocessing/errors/init.py", line 346, in wrapper
return f(*args, **kwargs)
File "/root/miniconda3/lib/python3.8/site-packages/torch/distributed/run.py", line 794, in main
run(args)
File "/root/miniconda3/lib/python3.8/site-packages/torch/distributed/run.py", line 785, in run
elastic_launch(
File "/root/miniconda3/lib/python3.8/site-packages/torch/distributed/launcher/api.py", line 134, in call
return launch_agent(self._config, self._entrypoint, list(args))
File "/root/miniconda3/lib/python3.8/site-packages/torch/distributed/launcher/api.py", line 250, in launch_agent
raise ChildFailedError(
torch.distributed.elastic.multiprocessing.errors.ChildFailedError:
/root/autodl-tmp/swift/swift/cli/sft.py FAILED
Failures:
<NO_OTHER_FAILURES>
Root Cause (first observed failure):
[0]:
time      : 2024-05-30_16:45:42
host      : autodl-container-ade5118aae-191466bc
rank      : 0 (local_rank: 0)
exitcode  : 1 (pid: 26529)
error_file: <N/A>
traceback : To enable traceback see: https://pytorch.org/docs/stable/elastic/errors.html
Your hardware and system info
Write your system info like CUDA version/system/GPU/torch version here(在这里给出硬件信息和系统信息，如CUDA版本，系统，GPU型号和torch版本等)
这是cuda版本
root@autodl-container-ade5118aae-191466bc:~/autodl-tmp# pip show torch
Name: torch
Version: 2.0.0+cu118
Summary: Tensors and Dynamic neural networks in Python with strong GPU acceleration
Home-page: https://pytorch.org/
Author: PyTorch Team
Author-email: packages@pytorch.org
License: BSD-3
Location: /root/miniconda3/lib/python3.8/site-packages
Requires: jinja2, triton, networkx, typing-extensions, filelock, sympy
Required-by: xtuner, trl, triton, torchvision, peft, optimum, flash-attn, bitsandbytes, accelerate
root@autodl-container-ade5118aae-191466bc:~/autodl-tmp# pip show transformers
Name: transformers
Version: 4.40.2
Summary: State-of-the-art Machine Learning for JAX, PyTorch and TensorFlow
Home-page: https://github.com/huggingface/transformers
Author: The Hugging Face team (past and future) with the help of all our contributors (https://github.com/huggingface/transformers/graphs/contributors)
Author-email: transformers@huggingface.co
License: Apache 2.0 License
Location: /root/miniconda3/lib/python3.8/site-packages
Requires: tokenizers, packaging, regex, pyyaml, tqdm, safetensors, huggingface-hub, numpy, filelock, requests
Required-by: xtuner, trl, transformers-stream-generator, peft, optimum, ms-swift
root@autodl-container-ade5118aae-191466bc:~/autodl-tmp#
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 525.105.17   Driver Version: 525.105.17   CUDA Version: 12.0     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|                               |                      |               MIG M. |
|===============================+======================+======================|
|   0  NVIDIA A40          On   | 00000000:01:00.0 Off |                  Off |
|  0%   23C    P8    22W / 300W |      2MiB / 49140MiB |      0%      Default |
|                               |                      |                  N/A |
+-------------------------------+----------------------+----------------------+
|   1  NVIDIA A40          On   | 00000000:41:00.0 Off |                  Off |
|  0%   21C    P8    12W / 300W |      2MiB / 49140MiB |      0%      Default |
|                               |                      |                  N/A |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes:                                                                  |
|  GPU   GI   CI        PID   Type   Process name                  GPU Memory |
|        ID   ID                                                   Usage      |
|=============================================================================|
|  No running processes found                                                 |
+-----------------------------------------------------------------------------+
Additional context
Add any other context about the problem here(在这里补充其他信息)

贴一下命令 我帮你看看吧

fixed

authors: Anorid Jintao-Huang

repo: modelscope/swift


text:
🛑 NZBHydra2 is down

In 759105f, NZBHydra2 ($HYDRA_URL) was down:

HTTP code: 521
Response time: 190 ms

Resolved: NZBHydra2 is back up in 2eadb59.


text:
🛑 Sonarr is down

In 992def0, Sonarr ($SONARR_URL) was down:

HTTP code: 521
Response time: 253 ms

Resolved: Sonarr is back up in 62d2ebc.


text:
🛑 Sonarr is down

In 5e8b9bb, Sonarr ($SONARR_URL) was down:

HTTP code: 521
Response time: 222 ms

Resolved: Sonarr is back up in d7d8b32.


text:
BUG: Exception: TypeError("object of type 'coroutine' has no len()")

System information

OS Platform and Distribution: Zorin OS 16.1
Modin version: 0.15.2
Python version: 3.9.12
Code we can use to reproduce:

state_unique = df['STATE'].unique().tolist()
state_and_county = {state: df[df.STATE == state].COUNTY.mode()
                         for state in state_unique}

def fill(state_id):
    try:
        return state_and_county[state_id].values[0]
    except:
        return np.nan

df['state'].apply(fill)

The dataset used is available here.
Describe the problem

When trying to apply a function element wise on a Pandas Series, it throws back Exception: TypeError("object of type 'coroutine' has no len()"). I reran the code using traditional Pandas and it worked fine.
Source code / logs

The full traceback is available here

@kareemamrr thanks for opening the issue! I'll take a look into it and see what's going on here.
This seems related to what some people saw here: https://github.com/modin-project/modin/issues/2498
@RehanSD could you please take a look?

@mvashishtha could you please take a look at this issue?

@kareemamrr thank you for reporting this issue. I was able to reproduce it with a short script that I edited into your original post. The bug seems to apply when a UDF uses a Modin object from the local scope. When the Dask worker initializes the Modin dataframe from its pickled form, we have two problems: (1) the worker is trying to initialize its own dask cluster (2) it seems client.ncores() is returning a coroutine instead of a dict as it normally does: https://github.com/modin-project/modin/blob/41e32e9edcd1e6755d6f959e573f807a75c7ae7e/modin/core/execution/dask/common/utils.py#L49
@kareemamrr To work around the bug, I would suggest either switching to Ray, or using a groupby instead of accessing the outer frame within fill. e.g. if you do the following
import pandas

state_and_modes = df[['STATE', 'COUNTY']].groupby('STATE', as_index=False).agg(pandas.Series.mode)
df['STATE'].to_frame().merge(state_and_county, on='STATE', how='left')['COUNTY']

you can get a series with the most common county for each state.
cc @YarShev in case you have thoughts about how to deal with this, because I see you commented about a fix for a similar case in tests here.

authors: kareemamrr mvashishtha pyrito

repo: modin-project/modin


text:
Switch to OmniSci from conda-forge

What do these changes do?
Switch to OmniSci-published packages.

[x] commit message follows format outlined here
[x] passes flake8 modin
[x] passes black --check modin
[x] signed commit with git commit -s
[x] Resolves #3057
[x] tests added and passing
[x] module layout described at docs/developer/architecture.rst is up-to-date

Converting to draft until we're completely ready for the switch.

So now there is no block. Can you rebase? @vnlitvinov

There's no need, we've decided with @Garra1980 to leave it in draft for the time being.

this can be dropped, I suppose?

This depends. I think we should actually revive it given it's effectively conda-forge version of OmniSci which is shipped as part of Intel AI Kit.

I meant we can close this as we already switched to Omnisci in c-f

Right, superseded by #3308.

authors: Garra1980 anmyachev vnlitvinov


text:
fixing url to follow URL security change

Changing git:// to https:// to follow security change
https://github.blog/2021-09-01-improving-git-protocol-security-github/#how-do-i-prepare

Just wanted to +1 this pull request since it has been out there for a while.  Admins, if you get a chance to merge, it's a very quick fix and it makes the package possible to install via pip again for those following the README.  Thanks @allevity !

authors: allevity bowmnath

repo: modusdatascience/choldate


text:
The license and the credit of leakcanary

I saw you use a lot of UI of leakcanary, probably some of the content of the README. And leakcanary is inder Apache 2.0.
You did not use that license, and give any credit neither.

I use that license (https://github.com/moduth/blockcanary/blob/master/LICENSE), just miss them in java files, will add soon later. @liaohuqiu

@liaohuqiu have added license in all java files, please check

Great! :beers:

authors: liaohuqiu markzhai

repo: moduth/blockcanary


text:
I need to install but it wont allow as root

WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead
Fix
use sudo instead from another non root user

Fix
use sudo instead from another non root user


text:
Fixed healthCheck command issue

command within healthcheck isn't a String.
Its a object as below:
{
"value": "COMMAND goes here"
}
getApps will fail with below exception if at all if any app has command healthcheck:
Caused by: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected a string but was BEGIN_OBJECT at line 1 column 499709 path $.apps[0].healthChecks[0].command
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:187)
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:40)
at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:81)
at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:60)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:95)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:183)
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:40)
at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:81)
at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:60)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:95)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:183)
at com.google.gson.Gson.fromJson(Gson.java:805)
at com.google.gson.Gson.fromJson(Gson.java:770)
at feign.gson.GsonDecoder.decode(GsonDecoder.java:55)
at feign.SynchronousMethodHandler.decode(SynchronousMethodHandler.java:161)
... 11 more
Caused by: java.lang.IllegalStateException: Expected a string but was BEGIN_OBJECT at line 1 column 499709 path $.apps[0].healthChecks[0].command
at com.google.gson.stream.JsonReader.nextString(JsonReader.java:836)
at com.google.gson.internal.bind.TypeAdapters$13.read(TypeAdapters.java:358)
at com.google.gson.internal.bind.TypeAdapters$13.read(TypeAdapters.java:346)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:95)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:183)
... 25 more
Fixed the above issue.

@mohitsoni Please review and merge. This is causing an issue in our application while getting apps.

@mohitsoni  Any update on this?

@sumannewton I'm no longer maintaining this project, please use: http://github.com/mesosphere/marathon-client

authors: mohitsoni sumannewton

repo: mohitsoni/marathon-client


text:
Add windows vista support

This PR add windows vista support.
It depend on the PR#6, so please merge the #6 before this one.
On windows vista (excluding windows vista sp2), DirectWrite, is not available. GDI is available, but it cannot query the font filename.
The only ways I know to get the font is to use the Shell to obtain the font filename.
From this website, we can see: Note that Python 3.8.1 cannot be used on Windows XP or earlier.
So, with this PR, we support all the possible windows version to get the font filename.

Finally, it isn't a good way to retrieve font.
For example, it doesn't return the font C:\Windows\Fonts\Marlett.ttf, but the font can still be queried by GDI or DirectWrite.


text:
input flag to ignore the output cells?

I was wondering if its possible to only cat the input cells of the notebook and ignore the output cells
sometimes the output of a cell can be super lengthy making the scroll tedious
and sometimes I just want to get an idea of whats going on in the file quickly

Thanks for the feature request!
I added it in https://github.com/moisutsu/nbcat/pull/7 and released it as v0.2.7👍

authors: DanishjeetSingh moisutsu

repo: moisutsu/nbcat


text:
Compute number of comparisons generated from a blocking rule by programatically maniupulating the physical plan from explain()

The physical plan will look something like:
== Physical Plan ==
*(5) Project [first_name#1343 AS first_name_l#1355, first_name#1361 AS first_name_r#1356, surname#1344 AS surname_l#1357, surname#1362 AS surname_r#1358, city#1345 AS city_l#1359, city#1363 AS city_r#1360]
+- *(5) SortMergeJoin [city#1345], [city#1363], Inner, ((random_int#1346L = random_int#1346L) OR (random_int#1346L = random_int#1364L))
   :- *(2) Sort [city#1345 ASC NULLS FIRST], false, 0
   :  +- Exchange hashpartitioning(city#1345, 20), ENSURE_REQUIREMENTS, [id=#3279]
   :     +- *(1) Filter isnotnull(city#1345)
   :        +- *(1) Scan ExistingRDD[first_name#1343,surname#1344,city#1345,random_int#1346L]
   +- *(4) Sort [city#1363 ASC NULLS FIRST], false, 0
      +- ReusedExchange [first_name#1361, surname#1362, city#1363, random_int#1364L], Exchange hashpartitioning(city#1345, 20), ENSURE_REQUIREMENTS, [id=#3279]

There are three places in this plan where we can infer that the number of records generated is going to be based on the city equality condition:
Exchange hashpartitioning on city, subsequent sort on city and then the sortmergejoin on city.    What we're looking for is hashpartitioning WITHIN SortMergeJoin - this should guarantee we choose the columns.
Note this would not work on a name inversion blocking rule, but it does work on an expression e.g. substring would be
Exchange hashpartitioning(substr(city#1457, 1, 2), 20), ENSURE_REQUIREMENTS, [id=#3615]

Another approach could simply to ingest the blocking rule, run it, and do a count(), which is much less expensive than trying to run the actual Splink job.
If you wanted to get clever, you could even do a count on a 0.1% sample first to check that doesn't blow up, before doing it on the whole thing.

Looks like there's a json representation that we can use like:
qe = df._jdf.queryExecution()
sp = qe.sparkPlan()
print(sp.prettyJson())

Unfortunately ☝ isn't quite what we need in the case of the join being on a function (e.g. substring(l.first_name,1,2) = substring(r.first_name,1,2)
In that case, the json contains the following, which unfortunately does not contain the sql expression we need:
[{'class': 'org.apache.spark.sql.catalyst.expressions.Substring',
  'num-children': 3,
  'str': 0,
  'pos': 1,
  'len': 2},
 {'class': 'org.apache.spark.sql.catalyst.expressions.AttributeReference',
  'num-children': 0,
  'name': 'first_name',
  'dataType': 'string',
  'nullable': True,
  'metadata': {},
  'exprId': {'product-class': 'org.apache.spark.sql.catalyst.expressions.ExprId',
   'id': 1,
   'jvmId': '6573b124-7296-462d-99de-ce364ad3a227'},
  'qualifier': '[l]'},
 {'class': 'org.apache.spark.sql.catalyst.expressions.Literal',
  'num-children': 0,
  'value': '1',
  'dataType': 'integer'},
 {'class': 'org.apache.spark.sql.catalyst.expressions.Literal',
  'num-children': 0,
  'value': '3',
  'dataType': 'integer'}]

repo: moj-analytical-services/splink


text:
Parse StructType columns in case expressions

Fixes #309

Looks good - need to bump version in pyproject.toml then we can merge

authors: RobinL samnlindsay