Skip to content

Pv creation helper#144

Merged
GDYendell merged 10 commits intomainfrom
pv_creation_helper
May 23, 2025
Merged

Pv creation helper#144
GDYendell merged 10 commits intomainfrom
pv_creation_helper

Conversation

@LuisFSegalla
Copy link
Contributor

@LuisFSegalla LuisFSegalla commented Mar 24, 2025

Added a single helper function to convert PV names into Pascal case and replace both "-" and "_" characters.

I'm opening the PR to discuss if more actions might be necessary for the helper as it's currently not checking for any other characters (like "/", "%". ...) and it required a small change in the tests that I'm not entirely sure is correct.

Closes #42

@LuisFSegalla LuisFSegalla requested a review from GDYendell March 24, 2025 15:12
@codecov
Copy link

codecov bot commented Mar 24, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 91.74%. Comparing base (afd3ad4) to head (5e59322).
Report is 3 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #144      +/-   ##
==========================================
- Coverage   91.84%   91.74%   -0.10%     
==========================================
  Files          40       40              
  Lines        1961     1962       +1     
==========================================
- Hits         1801     1800       -1     
- Misses        160      162       +2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@GDYendell
Copy link
Contributor

This new function should replace the one in fastcs.util and it should not be private. That function is (rightly or wrongly) used by fastcs-odin for converting names.

If this new method does not succeed in converting to PascalCase it will still be possible to get pvi validation errors, but that is probably OK. Could you try to provoke this in a test?

It would be good to have a unit test for the function parameterized with various combinations that it handles and does not handle.

@LuisFSegalla
Copy link
Contributor Author

Sure! I can do those changes.
What would we consider as a failure to convert? Just not being able to remove non-alphanumerical characters, like @evvaaaa suggested in the issue? Should this be handled in the function or we just let PVI handle it?

@GDYendell
Copy link
Contributor

Sorry I meant we want the function that is currently in pva, because I think that is a better implementation, but we want it to replace the one in fastcs.util.

Thanks that test is useful. I am thinking that this function should just do exactly what it says it does and not even handle dashes instead of underscores. We could do a second pass where we try to make this more generally useful. Something else we could do is enforce snake case when adding to Controller.attributes, as the context of the error will be in the driver code and be much more useful than when calling the pvi function.

@LuisFSegalla
Copy link
Contributor Author

Oh my bad!!
I'll return the method to what it was.
When you say to enforce snake case when adding to the Controller attributes you mean this line? Or would that be someting that each driver implementation should handle?

@GDYendell
Copy link
Contributor

I guess I was thinking what pydantic does when validating a serialised form, but we can't do that here so would need to do something else. Maybe a method for adding to Controller.attributes that does the check, rather than accessing. We can do this in another issue, though.

@GDYendell
Copy link
Contributor

I am not sure why the existing function has 3 steps. I think it should just be

re.sub(r"(?:^|_)([a-z])", lambda m: m.group(1).upper(), s)

This doesn't assert the full match, so we get "name_with-different_separators" -> "NameWith-differentSeparators", which is a bit odd, so it should also return the original if it is not snake case.

if not re.fullmatch(r"[a-z]+(?:_[a-z]+)*", s):
    return s

This may be a bit limiting, but at least it is clear what it is doing. It could be extended in future.

@LuisFSegalla
Copy link
Contributor Author

That makes sense!
I think the method was originally implemented with 3 steps here. But I agree it's a bit redundant.
While checking if the string is a valid snake case, should we also look for numbers in the middle/end of it?

@GDYendell
Copy link
Contributor

Yes good point. It should allow digits too (just not for the first character).

@GDYendell GDYendell marked this pull request as ready for review April 8, 2025 15:39
@GDYendell
Copy link
Contributor

OK I think this ready now, but I would like to try it with PandA, Eiger and Odin to make sure it doesn't break things. @LuisFSegalla have you been testing this branch againts fastcs-odin? @jsouter would you be able to try this branch with PandA and Eiger to see if it looks OK?

@LuisFSegalla
Copy link
Contributor Author

I tested agianst fastcs-odin (main branch) and fastcs-xspress (update-adapter) and nothing broke!

@jsouter
Copy link
Contributor

jsouter commented May 21, 2025

fastcs-PandABlocks seems to run okay against this, and the tests that are there pass. This is the output for the top level PVI.

pvget LAB-PANDA:PVI
LAB-PANDA:PVI structure 
    alarm_t alarm 
        int severity 0
        int status 0
        string message 
    time_t timeStamp 2025-05-21 09:19:39.608  
        long secondsPastEpoch 1747815579
        int nanoseconds 607922792
    structure value
        structure bits
            string d LAB-PANDA:Bits:PVI
        structure calc
            structure d
                string v1 LAB-PANDA:calc1:PVI
                string v2 LAB-PANDA:calc2:PVI
        structure clock
            structure d
                string v1 LAB-PANDA:clock1:PVI
                string v2 LAB-PANDA:clock2:PVI
        structure counter
            structure d
                string v1 LAB-PANDA:counter1:PVI
                string v2 LAB-PANDA:counter2:PVI
                string v3 LAB-PANDA:counter3:PVI
                string v4 LAB-PANDA:counter4:PVI
                string v5 LAB-PANDA:counter5:PVI
                string v6 LAB-PANDA:counter6:PVI
                string v7 LAB-PANDA:counter7:PVI
                string v8 LAB-PANDA:counter8:PVI
        structure div
            structure d
                string v1 LAB-PANDA:div1:PVI
                string v2 LAB-PANDA:div2:PVI
        structure filter
            structure d
                string v1 LAB-PANDA:filter1:PVI
                string v2 LAB-PANDA:filter2:PVI
        structure inenc
            structure d
                string v1 LAB-PANDA:inenc1:PVI
                string v2 LAB-PANDA:inenc2:PVI
                string v3 LAB-PANDA:inenc3:PVI
                string v4 LAB-PANDA:inenc4:PVI
        structure lut
            structure d
                string v1 LAB-PANDA:lut1:PVI
                string v2 LAB-PANDA:lut2:PVI
                string v3 LAB-PANDA:lut3:PVI
                string v4 LAB-PANDA:lut4:PVI
                string v5 LAB-PANDA:lut5:PVI
                string v6 LAB-PANDA:lut6:PVI
                string v7 LAB-PANDA:lut7:PVI
                string v8 LAB-PANDA:lut8:PVI
        structure lvdsin
            structure d
                string v1 LAB-PANDA:lvdsin1:PVI
                string v2 LAB-PANDA:lvdsin2:PVI
        structure lvdsout
            structure d
                string v1 LAB-PANDA:lvdsout1:PVI
                string v2 LAB-PANDA:lvdsout2:PVI
        structure outenc
            structure d
                string v1 LAB-PANDA:outenc1:PVI
                string v2 LAB-PANDA:outenc2:PVI
                string v3 LAB-PANDA:outenc3:PVI
                string v4 LAB-PANDA:outenc4:PVI
        structure pcap
            string d LAB-PANDA:Pcap:PVI
        structure pcomp
            structure d
                string v1 LAB-PANDA:pcomp1:PVI
                string v2 LAB-PANDA:pcomp2:PVI
        structure pgen
            structure d
                string v1 LAB-PANDA:pgen1:PVI
                string v2 LAB-PANDA:pgen2:PVI
        structure pulse
            structure d
                string v1 LAB-PANDA:pulse1:PVI
                string v2 LAB-PANDA:pulse2:PVI
                string v3 LAB-PANDA:pulse3:PVI
                string v4 LAB-PANDA:pulse4:PVI
        structure seq
            structure d
                string v1 LAB-PANDA:seq1:PVI
                string v2 LAB-PANDA:seq2:PVI
        structure sfp2_sync_in
            string d LAB-PANDA:sfp2_sync_in:PVI
        structure sfp2_sync_out
            string d LAB-PANDA:sfp2_sync_out:PVI
        structure sfp3_sync_in
            string d LAB-PANDA:sfp3_sync_in:PVI
        structure sfp3_sync_out
            string d LAB-PANDA:sfp3_sync_out:PVI
        structure srgate
            structure d
                string v1 LAB-PANDA:srgate1:PVI
                string v2 LAB-PANDA:srgate2:PVI
                string v3 LAB-PANDA:srgate3:PVI
                string v4 LAB-PANDA:srgate4:PVI
        structure system
            string d LAB-PANDA:System:PVI
        structure ttlin
            structure d
                string v1 LAB-PANDA:ttlin1:PVI
                string v2 LAB-PANDA:ttlin2:PVI
                string v3 LAB-PANDA:ttlin3:PVI
                string v4 LAB-PANDA:ttlin4:PVI
                string v5 LAB-PANDA:ttlin5:PVI
                string v6 LAB-PANDA:ttlin6:PVI
        structure ttlout
            structure d
                string v1 LAB-PANDA:ttlout1:PVI
                string v2 LAB-PANDA:ttlout2:PVI
                string v3 LAB-PANDA:ttlout3:PVI
                string v4 LAB-PANDA:ttlout4:PVI
                string v5 LAB-PANDA:ttlout5:PVI
                string v6 LAB-PANDA:ttlout6:PVI
                string v7 LAB-PANDA:ttlout7:PVI
                string v8 LAB-PANDA:ttlout8:PVI
                string v9 LAB-PANDA:ttlout9:PVI
                string v10 LAB-PANDA:ttlout10:PVI
        structure data
            string d LAB-PANDA:Data:PVI
        structure versions
            string d LAB-PANDA:Versions:PVI

and for one of the blocks

LAB-PANDA:ttlin1:PVI structure 
    alarm_t alarm 
        int severity 0
        int status 0
        string message 
    time_t timeStamp 2025-05-21 09:19:39.619  
        long secondsPastEpoch 1747815579
        int nanoseconds 619251489
    structure display
        string description TTL input
    structure value
        structure label
            string r LAB-PANDA:ttlin1:LABEL
        structure term
            string rw LAB-PANDA:ttlin1:Term
        structure val
            string r LAB-PANDA:ttlin1:Val
        structure val_capture
            string rw LAB-PANDA:ttlin1:ValCapture

but then some blocks are still snake cased

LAB-PANDA:sfp2_sync_in:PVI structure 
    alarm_t alarm 
        int severity 0
        int status 0
        string message 
    time_t timeStamp 2025-05-21 09:19:39.617  
        long secondsPastEpoch 1747815579
        int nanoseconds 617438793
    structure display
        string description sfp panda synchronizer
    structure value
        structure label
            string r LAB-PANDA:sfp2_sync_in:LABEL
        structure sync_reset
            string w LAB-PANDA:sfp2_sync_in:SyncReset
        structure linkup
            string r LAB-PANDA:sfp2_sync_in:Linkup
        structure bit1
            string r LAB-PANDA:sfp2_sync_in:bit1
        structure bit1_capture
            string rw LAB-PANDA:sfp2_sync_in:bit1_capture
        structure bit2
            string r LAB-PANDA:sfp2_sync_in:bit2
        structure bit2_capture
            string rw LAB-PANDA:sfp2_sync_in:bit2_capture
        structure bit3
            string r LAB-PANDA:sfp2_sync_in:bit3
        structure bit3_capture
            string rw LAB-PANDA:sfp2_sync_in:bit3_capture
        structure bit4
            string r LAB-PANDA:sfp2_sync_in:bit4
        structure bit4_capture
            string rw LAB-PANDA:sfp2_sync_in:bit4_capture
        structure bit5
            string r LAB-PANDA:sfp2_sync_in:bit5
        structure bit5_capture
            string rw LAB-PANDA:sfp2_sync_in:bit5_capture
        structure bit6
            string r LAB-PANDA:sfp2_sync_in:bit6
        structure bit6_capture
            string rw LAB-PANDA:sfp2_sync_in:bit6_capture
        structure bit7
            string r LAB-PANDA:sfp2_sync_in:bit7
        structure bit7_capture
            string rw LAB-PANDA:sfp2_sync_in:bit7_capture
        structure bit8
            string r LAB-PANDA:sfp2_sync_in:bit8
        structure bit8_capture
            string rw LAB-PANDA:sfp2_sync_in:bit8_capture
        structure pos1
            string r LAB-PANDA:sfp2_sync_in:pos1
        structure pos1_scale
            string rw LAB-PANDA:sfp2_sync_in:pos1_scale
        structure pos1_offset
            string rw LAB-PANDA:sfp2_sync_in:pos1_offset
        structure pos1_scaled
            string r LAB-PANDA:sfp2_sync_in:pos1_scaled
        structure pos1_capture
            string rw LAB-PANDA:sfp2_sync_in:pos1_capture
        structure pos1_dataset
            string rw LAB-PANDA:sfp2_sync_in:pos1_dataset
        structure pos2
            string r LAB-PANDA:sfp2_sync_in:pos2
        structure pos2_scale
            string rw LAB-PANDA:sfp2_sync_in:pos2_scale
        structure pos2_offset
            string rw LAB-PANDA:sfp2_sync_in:pos2_offset
        structure pos2_scaled
            string r LAB-PANDA:sfp2_sync_in:pos2_scaled
        structure pos2_capture
            string rw LAB-PANDA:sfp2_sync_in:pos2_capture
        structure pos2_dataset
            string rw LAB-PANDA:sfp2_sync_in:pos2_dataset
        structure pos3
            string r LAB-PANDA:sfp2_sync_in:pos3
        structure pos3_scale
            string rw LAB-PANDA:sfp2_sync_in:pos3_scale
        structure pos3_offset
            string rw LAB-PANDA:sfp2_sync_in:pos3_offset
        structure pos3_scaled
            string r LAB-PANDA:sfp2_sync_in:pos3_scaled
        structure pos3_capture
            string rw LAB-PANDA:sfp2_sync_in:pos3_capture
        structure pos3_dataset
            string rw LAB-PANDA:sfp2_sync_in:pos3_dataset
        structure pos4
            string r LAB-PANDA:sfp2_sync_in:pos4
        structure pos4_scale
            string rw LAB-PANDA:sfp2_sync_in:pos4_scale
        structure pos4_offset
            string rw LAB-PANDA:sfp2_sync_in:pos4_offset
        structure pos4_scaled
            string r LAB-PANDA:sfp2_sync_in:pos4_scaled
        structure pos4_capture
            string rw LAB-PANDA:sfp2_sync_in:pos4_capture
        structure pos4_dataset
            string rw LAB-PANDA:sfp2_sync_in:pos4_dataset
        structure health
            string r LAB-PANDA:sfp2_sync_in:Health
        structure err_cnt
            string r LAB-PANDA:sfp2_sync_in:ErrCnt

@GDYendell
Copy link
Contributor

@shihab-dls could you test fastcs-eiger against this branch and try the ophyd device against it?

Updated public snake_to_pascal function and added tests for it.
Reverted to using regex logic on snake_to_pascal function and only
handle "_" character
Made function only convert strings that are valid snake case and removed
redundant code parts.
@GDYendell GDYendell force-pushed the pv_creation_helper branch from 203aea8 to d17abbb Compare May 22, 2025 09:36
@shihab-dls
Copy link
Contributor

@shihab-dls could you test fastcs-eiger against this branch and try the ophyd device against it?

I managed to run a brief dodal plan using the fastcs-eiger ophyd-async device against this PR (although with some unrelated hiccups on the odin side); tests also pass and PV names look good to me!

@GDYendell GDYendell merged commit 6ee1578 into main May 23, 2025
17 of 18 checks passed
@GDYendell GDYendell deleted the pv_creation_helper branch May 23, 2025 13:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add a helper for consistently creating PV names

4 participants