Skip to content

Conversation

@jacomago
Copy link
Contributor

@jacomago jacomago commented Nov 4, 2025

Large refactor of cfstore

  • Adds dataclasses to handle all the intemediary types rather than the usage of dictionaries for everything.
  • Swaps to snake case (where not using Twisted stuff)
  • Adds typing everywhere I can
  • Adds pydoc to every method
  • Splits up the bigger methods to be much smaller
  • Adds the full data structures to the log messages
  • Cleans up exception messages to include more debug information

@jacomago jacomago self-assigned this Nov 4, 2025
@jacomago jacomago force-pushed the refactor_cfstore_to_dataclasses branch 2 times, most recently from a303d96 to 5a4b537 Compare November 4, 2025 15:24
Copy link
Contributor

@simon-ess simon-ess left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall this is a clear improvement!

cf_channel["properties"].append(
create_recordType_property(
owner, iocs[channels_dict[cf_channel["name"]][-1]]["recordType"]
ioc_info.owner, iocs[channels_iocs[cf_channel["name"]][-1]]["recordType"]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be a .recordType here? We use .owner above on the same object...

(These objects are very confusing to follow... this is clearly going to be an improvement but ugh)

Comment on lines 618 to 625
alias_channel["properties"] = __merge_property_lists(
[
create_active_property(owner),
create_time_property(owner, iocTime),
],
alias,
alias_channel,
processor.managed_properties,
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not do this in the above row when you're declaring the dict? 🔧


if iocid not in iocs:
_log.warning("IOC Env Info not found: {iocid}".format(iocid=iocid))
_log.warning("IOC Env Info %s not found in ioc list: %s", ioc_info, iocs)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we please improve this msg/phrasing while we're at it? I hate "IOC Env Info"

):
for cf_channel in old_channels:
if (
len(new_channels) == 0 or cf_channel.name in records_to_delete
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No reason not to do not new_channels or ...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still seems to apply

@jacomago jacomago force-pushed the refactor_cfstore_to_dataclasses branch 2 times, most recently from 5c64534 to 2c90757 Compare November 6, 2025 09:35
@jacomago jacomago force-pushed the refactor_cfstore_to_dataclasses branch from 2c90757 to 2add230 Compare November 27, 2025 15:12
Copy link
Contributor

@anderslindho anderslindho left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll end the review here, as it looks unfinished from 2add230

@jacomago jacomago force-pushed the refactor_cfstore_to_dataclasses branch 3 times, most recently from 2a666e8 to 3375756 Compare December 1, 2025 14:52
@jacomago jacomago force-pushed the refactor_cfstore_to_dataclasses branch 2 times, most recently from 012aae6 to 919b9fa Compare December 1, 2025 15:34
In favour of create_property_blah
log the whole object when available
use inbuilt log formatting rather than f strings or .format (should improve performance)
@jacomago jacomago force-pushed the refactor_cfstore_to_dataclasses branch from 919b9fa to 3f68066 Compare December 2, 2025 12:17
Copy link
Contributor

@anderslindho anderslindho left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's pretty good, but IMO we should be fixing these remaining idiomatic python/PEP-8 issues before merge. Can all be in a single new commit if you want, TBH.

Comment on lines 36 to 37
Active = enum.auto()
Inactive = enum.auto()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thinking more about this, StrEnum is def the way to go - don't think we have any other option for CFPropertyName.

Comment on lines 22 to +23
from . import interfaces
from .interfaces import CommitTransaction
from .processors import ConfigAdapter
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should prob convert the project to use abs imports - could be done together with splitting up cfstore.py 💭

cf_query_limit: int = DEFAULT_QUERY_LIMIT

@classmethod
def loads(cls, conf: ConfigAdapter) -> "CFConfig":
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

loads usually means "load from string" (and then load is typically from file), but I guess this is OK because from_configadapter would be a bit odd/is not immediately clear (that class is a bit strange TBH)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do agree that I expect loads to be from a string, but I would otherwise interpret load as just kind of generic. So maybe it would be better in this case?

@jacomago jacomago force-pushed the refactor_cfstore_to_dataclasses branch from 211d19b to 26d6654 Compare December 5, 2025 14:49
@jacomago
Copy link
Contributor Author

jacomago commented Dec 5, 2025

@anderslindho I dropped the override commit, only supported on 3.12 and above.

cf_query_limit: int = DEFAULT_QUERY_LIMIT

@classmethod
def loads(cls, conf: ConfigAdapter) -> "CFConfig":
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do agree that I expect loads to be from a string, but I would otherwise interpret load as just kind of generic. So maybe it would be better in this case?

Comment on lines +92 to +102
def from_dict(cls, prop_dict: Dict[str, str]) -> "CFProperty":
"""Create CFProperty from Channelfinder json output.
Args:
prop_dict: Dictionary representing a property from Channelfinder.
"""
return cls(
name=prop_dict.get("name", ""),
owner=prop_dict.get("owner", ""),
value=prop_dict.get("value"),
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you really need this function? You can also allow defaults in the class definition and just do

CFProperty(**some_dict)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its the frustrating 'channels' field in the prop_dict :( that blocks doing it that way.

Comment on lines +225 to +236
@classmethod
def from_dict(cls, channel_dict: Dict[str, Any]) -> "CFChannel":
"""Create CFChannel from Channelfinder json output.
Args:
channel_dict: Dictionary representing a channel from Channelfinder.
"""
return cls(
name=channel_dict.get("name", ""),
owner=channel_dict.get("owner", ""),
properties=[CFProperty.from_dict(p) for p in channel_dict.get("properties", [])],
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same question as above.

Comment on lines +294 to +300
CFPropertyName.HOSTNAME.value,
CFPropertyName.IOC_NAME.value,
CFPropertyName.IOC_ID.value,
CFPropertyName.IOC_IP.value,
CFPropertyName.PV_STATUS.value,
CFPropertyName.TIME.value,
CFPropertyName.RECCEIVER_ID.value,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we actually need the .values here? Can we not just work with the enum entities?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is kind of a general question tbh - everywhere I saw the enums used they were used as their .value version. Can't they be let be except when you are printing them?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CFPropertyName is a tricky case as you mentioned, in that this is the 'default' property names. You can have them for the env variables and the info tags.

@tynanford
Copy link
Contributor

as the resident ancient python supporter, dataclasses are >= 3.7 and are backported to 3.6 via the pip package. That is fine with me but I thought it is worth mentioning for the 3.6 crowd

I think this is an interesting topic, @tynanford: should we continue to support EOL python versions for our new releases?

Personally I think there is value supporting 3.6 for the user community. It is EOL but it is the default python version on redhat and the RHEL variants. Redhat backports security fixes to 3.6 and will until 2029. Not saying we need to continue 3.6 support until then but I also don't see a big reason to drop it now

@jacomago jacomago force-pushed the refactor_cfstore_to_dataclasses branch from 26d6654 to f74749e Compare December 8, 2025 12:25
@sonarqubecloud
Copy link

sonarqubecloud bot commented Dec 8, 2025

@jacomago jacomago requested a review from anderslindho December 8, 2025 12:47
@jacomago
Copy link
Contributor Author

jacomago commented Dec 8, 2025

@jacomago jacomago merged commit 5be70cb into master Dec 8, 2025
33 of 34 checks passed
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.

5 participants