Add ConfigStore support - #34

Merged
posborne merged 4 commits into
mainfrom
posborne/config-store
Feb 17, 2026
Merged

Add ConfigStore support#34
posborne merged 4 commits into
mainfrom
posborne/config-store

Conversation

@posborne

Copy link
Copy Markdown
Member

Mirroring the JS SDK, we provide a simple get() interface. I opted to not trying to provide a dict facade or similar. That is possible but it doesn't seem to represent a significant ergonomic improvement and might make it more likely that user's fail to keep in mind the potential exception behavior.

As with the Rust SDK, we intelligently use hint information from the host to get values with a big enough buffer if our original size is insufficient.


Potential discussion points:

  • I chose not to make the store look like a dict; this is possible but I don't feel it adds much and might be too lossy a mapping vs. just providing get/contains.
  • We don't have a strongly established resource pattern; here I take the approach of:
    • Context Manager + close
    • We do exit explicitly on the underlying resource rather than relying on the gc (if context manager or close() are used).
    • We don't try to provide an exception if use-after-close is performed, we document that the code will trap.

I expect to rework this code when the unified exception mapping is present, but feel there is enough here to review the important bits.

@erikroseerikrose left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

As much a note to myself as to you, but…

It looks like what this class adds (in addition to some very nice docs) is…

  1. Auto buffer sizing (yay)
  2. A close() method

Otherwise, the API looks parallel to what we'd get from the generated class, which would be…

fromwit_world.imports.config_storeimportStorewithStore.open("someConfig") asconfig:
print(config.get("someKey"), 1024) # and hope for the best bufferwise

See you in a few minutes! Oh, also, I'd prefer to subsume open() into __init__() so you can just ConfigStore("someStore").

@dgohman-fastly

Copy link
Copy Markdown
Contributor

As with the Rust SDK, we intelligently use hint information from the host to get values with a big enough buffer if our original size is insufficient.

The buffer len arguments are there for the benefit of the component adapter, which has to work with fixed-sized buffers passed in by the user code through the witx ABI. For code using WIT bindings directly, it's ok to just let the host call back into the guest with cabi_realloc with whatever length is needed. So the Python SDK here should be able to just pass the maximum u64 value to all the max-len arguments. That way it'll just never see buffer-len errors.

Mirroring the JS SDK, we provide a simple get() interface. I opted
to not trying to provide a dict facade or similar. That is possible
but it doesn't seem to represent a significant ergonomic improvement
and might make it more likely that user's fail to keep in mind the
potential exception behavior.
As with the Rust SDK, we intelligently use hint information from
the host to get values with a big enough buffer if our original
size is insufficient.
@posborne
posborneforce-pushed the posborne/config-store branch from 5bb9633 to e188cbaCompareFebruary 4, 2026 03:30
Also, use larger buffer size rather than doing
unecessary resizes and address a few other comments
from the PR.
@posborne
posborneforce-pushed the posborne/config-store branch from e188cba to e803f69CompareFebruary 4, 2026 03:34
@posborne

Copy link
Copy Markdown
MemberAuthor

I rebased these changes on the latest upstream; comments that are related can be found on the logging PR related to introduction of an inheritance hierarchy and open() vs __init__ and potential fallibility.

The exceptions that are generated now are buried fairly deep which could be a bit challenging for users to work with. We max need to fix some stuff later on but I tried to document each of those potential exceptions explicitly so end-users know where they may need to dig to import appropriate exceptions.

Comment threadfastly_compute/config_store.py Outdated
Comment threadfastly_compute/config_store.py Outdated
@erikrose

Copy link
Copy Markdown
Member

The exceptions that are generated now are buried fairly deep which could be a bit challenging for users to work with.

I wrote up a proposal on that: #41.

@erikroseerikrose left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looks good! Let's get it in.

@posborne
posborne merged commit c4b16ee into mainFeb 17, 2026
3 checks passed
@posborne
posborne deleted the posborne/config-store branch February 17, 2026 21:13
Sign up for freeto 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.

3 participants

@posborne@dgohman-fastly@erikrose
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Add ConfigStore support - #34

Merged
posborne merged 4 commits into
mainfrom
posborne/config-store
Feb 17, 2026
Merged

Add ConfigStore support#34
posborne merged 4 commits into
mainfrom
posborne/config-store

Conversation

@posborne

Copy link
Copy Markdown
Member

Mirroring the JS SDK, we provide a simple get() interface. I opted to not trying to provide a dict facade or similar. That is possible but it doesn't seem to represent a significant ergonomic improvement and might make it more likely that user's fail to keep in mind the potential exception behavior.

As with the Rust SDK, we intelligently use hint information from the host to get values with a big enough buffer if our original size is insufficient.


Potential discussion points:

  • I chose not to make the store look like a dict; this is possible but I don't feel it adds much and might be too lossy a mapping vs. just providing get/contains.
  • We don't have a strongly established resource pattern; here I take the approach of:
    • Context Manager + close
    • We do exit explicitly on the underlying resource rather than relying on the gc (if context manager or close() are used).
    • We don't try to provide an exception if use-after-close is performed, we document that the code will trap.

I expect to rework this code when the unified exception mapping is present, but feel there is enough here to review the important bits.

@erikroseerikrose left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

As much a note to myself as to you, but…

It looks like what this class adds (in addition to some very nice docs) is…

  1. Auto buffer sizing (yay)
  2. A close() method

Otherwise, the API looks parallel to what we'd get from the generated class, which would be…

fromwit_world.imports.config_storeimportStorewithStore.open("someConfig") asconfig:
print(config.get("someKey"), 1024) # and hope for the best bufferwise

See you in a few minutes! Oh, also, I'd prefer to subsume open() into __init__() so you can just ConfigStore("someStore").

@dgohman-fastly

Copy link
Copy Markdown
Contributor

As with the Rust SDK, we intelligently use hint information from the host to get values with a big enough buffer if our original size is insufficient.

The buffer len arguments are there for the benefit of the component adapter, which has to work with fixed-sized buffers passed in by the user code through the witx ABI. For code using WIT bindings directly, it's ok to just let the host call back into the guest with cabi_realloc with whatever length is needed. So the Python SDK here should be able to just pass the maximum u64 value to all the max-len arguments. That way it'll just never see buffer-len errors.

Mirroring the JS SDK, we provide a simple get() interface. I opted
to not trying to provide a dict facade or similar. That is possible
but it doesn't seem to represent a significant ergonomic improvement
and might make it more likely that user's fail to keep in mind the
potential exception behavior.
As with the Rust SDK, we intelligently use hint information from
the host to get values with a big enough buffer if our original
size is insufficient.
@posborne
posborneforce-pushed the posborne/config-store branch from 5bb9633 to e188cbaCompareFebruary 4, 2026 03:30
Also, use larger buffer size rather than doing
unecessary resizes and address a few other comments
from the PR.
@posborne
posborneforce-pushed the posborne/config-store branch from e188cba to e803f69CompareFebruary 4, 2026 03:34
@posborne

Copy link
Copy Markdown
MemberAuthor

I rebased these changes on the latest upstream; comments that are related can be found on the logging PR related to introduction of an inheritance hierarchy and open() vs __init__ and potential fallibility.

The exceptions that are generated now are buried fairly deep which could be a bit challenging for users to work with. We max need to fix some stuff later on but I tried to document each of those potential exceptions explicitly so end-users know where they may need to dig to import appropriate exceptions.

Comment threadfastly_compute/config_store.py Outdated
Comment threadfastly_compute/config_store.py Outdated
@erikrose

Copy link
Copy Markdown
Member

The exceptions that are generated now are buried fairly deep which could be a bit challenging for users to work with.

I wrote up a proposal on that: #41.

@erikroseerikrose left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looks good! Let's get it in.

@posborne
posborne merged commit c4b16ee into mainFeb 17, 2026
3 checks passed
@posborne
posborne deleted the posborne/config-store branch February 17, 2026 21:13
Sign up for freeto 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.

3 participants

@posborne@dgohman-fastly@erikrose
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add ConfigStore support - #34

Merged
posborne merged 4 commits into
mainfrom
posborne/config-store
Feb 17, 2026
Merged

Add ConfigStore support#34
posborne merged 4 commits into
mainfrom
posborne/config-store

Conversation

@posborne

Copy link
Copy Markdown
Member

Mirroring the JS SDK, we provide a simple get() interface. I opted to not trying to provide a dict facade or similar. That is possible but it doesn't seem to represent a significant ergonomic improvement and might make it more likely that user's fail to keep in mind the potential exception behavior.

As with the Rust SDK, we intelligently use hint information from the host to get values with a big enough buffer if our original size is insufficient.


Potential discussion points:

  • I chose not to make the store look like a dict; this is possible but I don't feel it adds much and might be too lossy a mapping vs. just providing get/contains.
  • We don't have a strongly established resource pattern; here I take the approach of:
    • Context Manager + close
    • We do exit explicitly on the underlying resource rather than relying on the gc (if context manager or close() are used).
    • We don't try to provide an exception if use-after-close is performed, we document that the code will trap.

I expect to rework this code when the unified exception mapping is present, but feel there is enough here to review the important bits.

@erikroseerikrose left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

As much a note to myself as to you, but…

It looks like what this class adds (in addition to some very nice docs) is…

  1. Auto buffer sizing (yay)
  2. A close() method

Otherwise, the API looks parallel to what we'd get from the generated class, which would be…

fromwit_world.imports.config_storeimportStorewithStore.open("someConfig") asconfig:
print(config.get("someKey"), 1024) # and hope for the best bufferwise

See you in a few minutes! Oh, also, I'd prefer to subsume open() into __init__() so you can just ConfigStore("someStore").

@dgohman-fastly

Copy link
Copy Markdown
Contributor

As with the Rust SDK, we intelligently use hint information from the host to get values with a big enough buffer if our original size is insufficient.

The buffer len arguments are there for the benefit of the component adapter, which has to work with fixed-sized buffers passed in by the user code through the witx ABI. For code using WIT bindings directly, it's ok to just let the host call back into the guest with cabi_realloc with whatever length is needed. So the Python SDK here should be able to just pass the maximum u64 value to all the max-len arguments. That way it'll just never see buffer-len errors.

Mirroring the JS SDK, we provide a simple get() interface. I opted
to not trying to provide a dict facade or similar. That is possible
but it doesn't seem to represent a significant ergonomic improvement
and might make it more likely that user's fail to keep in mind the
potential exception behavior.
As with the Rust SDK, we intelligently use hint information from
the host to get values with a big enough buffer if our original
size is insufficient.
@posborne
posborneforce-pushed the posborne/config-store branch from 5bb9633 to e188cbaCompareFebruary 4, 2026 03:30
Also, use larger buffer size rather than doing
unecessary resizes and address a few other comments
from the PR.
@posborne
posborneforce-pushed the posborne/config-store branch from e188cba to e803f69CompareFebruary 4, 2026 03:34
@posborne

Copy link
Copy Markdown
MemberAuthor

I rebased these changes on the latest upstream; comments that are related can be found on the logging PR related to introduction of an inheritance hierarchy and open() vs __init__ and potential fallibility.

The exceptions that are generated now are buried fairly deep which could be a bit challenging for users to work with. We max need to fix some stuff later on but I tried to document each of those potential exceptions explicitly so end-users know where they may need to dig to import appropriate exceptions.

Comment threadfastly_compute/config_store.py Outdated
Comment threadfastly_compute/config_store.py Outdated
@erikrose

Copy link
Copy Markdown
Member

The exceptions that are generated now are buried fairly deep which could be a bit challenging for users to work with.

I wrote up a proposal on that: #41.

@erikroseerikrose left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looks good! Let's get it in.

@posborne
posborne merged commit c4b16ee into mainFeb 17, 2026
3 checks passed
@posborne
posborne deleted the posborne/config-store branch February 17, 2026 21:13
Sign up for freeto 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.

3 participants

@posborne@dgohman-fastly@erikrose
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add ConfigStore support - #34

Merged
posborne merged 4 commits into
mainfrom
posborne/config-store
Feb 17, 2026
Merged

Add ConfigStore support#34
posborne merged 4 commits into
mainfrom
posborne/config-store

Conversation

@posborne

Copy link
Copy Markdown
Member

Mirroring the JS SDK, we provide a simple get() interface. I opted to not trying to provide a dict facade or similar. That is possible but it doesn't seem to represent a significant ergonomic improvement and might make it more likely that user's fail to keep in mind the potential exception behavior.

As with the Rust SDK, we intelligently use hint information from the host to get values with a big enough buffer if our original size is insufficient.


Potential discussion points:

  • I chose not to make the store look like a dict; this is possible but I don't feel it adds much and might be too lossy a mapping vs. just providing get/contains.
  • We don't have a strongly established resource pattern; here I take the approach of:
    • Context Manager + close
    • We do exit explicitly on the underlying resource rather than relying on the gc (if context manager or close() are used).
    • We don't try to provide an exception if use-after-close is performed, we document that the code will trap.

I expect to rework this code when the unified exception mapping is present, but feel there is enough here to review the important bits.

@erikroseerikrose left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

As much a note to myself as to you, but…

It looks like what this class adds (in addition to some very nice docs) is…

  1. Auto buffer sizing (yay)
  2. A close() method

Otherwise, the API looks parallel to what we'd get from the generated class, which would be…

fromwit_world.imports.config_storeimportStorewithStore.open("someConfig") asconfig:
print(config.get("someKey"), 1024) # and hope for the best bufferwise

See you in a few minutes! Oh, also, I'd prefer to subsume open() into __init__() so you can just ConfigStore("someStore").

@dgohman-fastly

Copy link
Copy Markdown
Contributor

As with the Rust SDK, we intelligently use hint information from the host to get values with a big enough buffer if our original size is insufficient.

The buffer len arguments are there for the benefit of the component adapter, which has to work with fixed-sized buffers passed in by the user code through the witx ABI. For code using WIT bindings directly, it's ok to just let the host call back into the guest with cabi_realloc with whatever length is needed. So the Python SDK here should be able to just pass the maximum u64 value to all the max-len arguments. That way it'll just never see buffer-len errors.

Mirroring the JS SDK, we provide a simple get() interface. I opted
to not trying to provide a dict facade or similar. That is possible
but it doesn't seem to represent a significant ergonomic improvement
and might make it more likely that user's fail to keep in mind the
potential exception behavior.
As with the Rust SDK, we intelligently use hint information from
the host to get values with a big enough buffer if our original
size is insufficient.
@posborne
posborneforce-pushed the posborne/config-store branch from 5bb9633 to e188cbaCompareFebruary 4, 2026 03:30
Also, use larger buffer size rather than doing
unecessary resizes and address a few other comments
from the PR.
@posborne
posborneforce-pushed the posborne/config-store branch from e188cba to e803f69CompareFebruary 4, 2026 03:34
@posborne

Copy link
Copy Markdown
MemberAuthor

I rebased these changes on the latest upstream; comments that are related can be found on the logging PR related to introduction of an inheritance hierarchy and open() vs __init__ and potential fallibility.

The exceptions that are generated now are buried fairly deep which could be a bit challenging for users to work with. We max need to fix some stuff later on but I tried to document each of those potential exceptions explicitly so end-users know where they may need to dig to import appropriate exceptions.

Comment threadfastly_compute/config_store.py Outdated
Comment threadfastly_compute/config_store.py Outdated
@erikrose

Copy link
Copy Markdown
Member

The exceptions that are generated now are buried fairly deep which could be a bit challenging for users to work with.

I wrote up a proposal on that: #41.

@erikroseerikrose left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looks good! Let's get it in.

@posborne
posborne merged commit c4b16ee into mainFeb 17, 2026
3 checks passed
@posborne
posborne deleted the posborne/config-store branch February 17, 2026 21:13
Sign up for freeto 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.

3 participants

@posborne@dgohman-fastly@erikrose
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Add ConfigStore support - #34

Merged
posborne merged 4 commits into
mainfrom
posborne/config-store
Feb 17, 2026
Merged

Add ConfigStore support#34
posborne merged 4 commits into
mainfrom
posborne/config-store

Conversation

@posborne

Copy link
Copy Markdown
Member

Mirroring the JS SDK, we provide a simple get() interface. I opted to not trying to provide a dict facade or similar. That is possible but it doesn't seem to represent a significant ergonomic improvement and might make it more likely that user's fail to keep in mind the potential exception behavior.

As with the Rust SDK, we intelligently use hint information from the host to get values with a big enough buffer if our original size is insufficient.


Potential discussion points:

  • I chose not to make the store look like a dict; this is possible but I don't feel it adds much and might be too lossy a mapping vs. just providing get/contains.
  • We don't have a strongly established resource pattern; here I take the approach of:
    • Context Manager + close
    • We do exit explicitly on the underlying resource rather than relying on the gc (if context manager or close() are used).
    • We don't try to provide an exception if use-after-close is performed, we document that the code will trap.

I expect to rework this code when the unified exception mapping is present, but feel there is enough here to review the important bits.

@erikroseerikrose left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

As much a note to myself as to you, but…

It looks like what this class adds (in addition to some very nice docs) is…

  1. Auto buffer sizing (yay)
  2. A close() method

Otherwise, the API looks parallel to what we'd get from the generated class, which would be…

fromwit_world.imports.config_storeimportStorewithStore.open("someConfig") asconfig:
print(config.get("someKey"), 1024) # and hope for the best bufferwise

See you in a few minutes! Oh, also, I'd prefer to subsume open() into __init__() so you can just ConfigStore("someStore").

@dgohman-fastly

Copy link
Copy Markdown
Contributor

As with the Rust SDK, we intelligently use hint information from the host to get values with a big enough buffer if our original size is insufficient.

The buffer len arguments are there for the benefit of the component adapter, which has to work with fixed-sized buffers passed in by the user code through the witx ABI. For code using WIT bindings directly, it's ok to just let the host call back into the guest with cabi_realloc with whatever length is needed. So the Python SDK here should be able to just pass the maximum u64 value to all the max-len arguments. That way it'll just never see buffer-len errors.

Mirroring the JS SDK, we provide a simple get() interface. I opted
to not trying to provide a dict facade or similar. That is possible
but it doesn't seem to represent a significant ergonomic improvement
and might make it more likely that user's fail to keep in mind the
potential exception behavior.
As with the Rust SDK, we intelligently use hint information from
the host to get values with a big enough buffer if our original
size is insufficient.
@posborne
posborneforce-pushed the posborne/config-store branch from 5bb9633 to e188cbaCompareFebruary 4, 2026 03:30
Also, use larger buffer size rather than doing
unecessary resizes and address a few other comments
from the PR.
@posborne
posborneforce-pushed the posborne/config-store branch from e188cba to e803f69CompareFebruary 4, 2026 03:34
@posborne

Copy link
Copy Markdown
MemberAuthor

I rebased these changes on the latest upstream; comments that are related can be found on the logging PR related to introduction of an inheritance hierarchy and open() vs __init__ and potential fallibility.

The exceptions that are generated now are buried fairly deep which could be a bit challenging for users to work with. We max need to fix some stuff later on but I tried to document each of those potential exceptions explicitly so end-users know where they may need to dig to import appropriate exceptions.

Comment threadfastly_compute/config_store.py Outdated
Comment threadfastly_compute/config_store.py Outdated
@erikrose

Copy link
Copy Markdown
Member

The exceptions that are generated now are buried fairly deep which could be a bit challenging for users to work with.

I wrote up a proposal on that: #41.

@erikroseerikrose left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looks good! Let's get it in.

@posborne
posborne merged commit c4b16ee into mainFeb 17, 2026
3 checks passed
@posborne
posborne deleted the posborne/config-store branch February 17, 2026 21:13
Sign up for freeto 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.

3 participants

@posborne@dgohman-fastly@erikrose
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add ConfigStore support - #34

Merged
posborne merged 4 commits into
mainfrom
posborne/config-store
Feb 17, 2026
Merged

Add ConfigStore support#34
posborne merged 4 commits into
mainfrom
posborne/config-store

Conversation

@posborne

Copy link
Copy Markdown
Member

Mirroring the JS SDK, we provide a simple get() interface. I opted to not trying to provide a dict facade or similar. That is possible but it doesn't seem to represent a significant ergonomic improvement and might make it more likely that user's fail to keep in mind the potential exception behavior.

As with the Rust SDK, we intelligently use hint information from the host to get values with a big enough buffer if our original size is insufficient.


Potential discussion points:

  • I chose not to make the store look like a dict; this is possible but I don't feel it adds much and might be too lossy a mapping vs. just providing get/contains.
  • We don't have a strongly established resource pattern; here I take the approach of:
    • Context Manager + close
    • We do exit explicitly on the underlying resource rather than relying on the gc (if context manager or close() are used).
    • We don't try to provide an exception if use-after-close is performed, we document that the code will trap.

I expect to rework this code when the unified exception mapping is present, but feel there is enough here to review the important bits.

@erikroseerikrose left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

As much a note to myself as to you, but…

It looks like what this class adds (in addition to some very nice docs) is…

  1. Auto buffer sizing (yay)
  2. A close() method

Otherwise, the API looks parallel to what we'd get from the generated class, which would be…

fromwit_world.imports.config_storeimportStorewithStore.open("someConfig") asconfig:
print(config.get("someKey"), 1024) # and hope for the best bufferwise

See you in a few minutes! Oh, also, I'd prefer to subsume open() into __init__() so you can just ConfigStore("someStore").

@dgohman-fastly

Copy link
Copy Markdown
Contributor

As with the Rust SDK, we intelligently use hint information from the host to get values with a big enough buffer if our original size is insufficient.

The buffer len arguments are there for the benefit of the component adapter, which has to work with fixed-sized buffers passed in by the user code through the witx ABI. For code using WIT bindings directly, it's ok to just let the host call back into the guest with cabi_realloc with whatever length is needed. So the Python SDK here should be able to just pass the maximum u64 value to all the max-len arguments. That way it'll just never see buffer-len errors.

Mirroring the JS SDK, we provide a simple get() interface. I opted
to not trying to provide a dict facade or similar. That is possible
but it doesn't seem to represent a significant ergonomic improvement
and might make it more likely that user's fail to keep in mind the
potential exception behavior.
As with the Rust SDK, we intelligently use hint information from
the host to get values with a big enough buffer if our original
size is insufficient.
@posborne
posborneforce-pushed the posborne/config-store branch from 5bb9633 to e188cbaCompareFebruary 4, 2026 03:30
Also, use larger buffer size rather than doing
unecessary resizes and address a few other comments
from the PR.
@posborne
posborneforce-pushed the posborne/config-store branch from e188cba to e803f69CompareFebruary 4, 2026 03:34
@posborne

Copy link
Copy Markdown
MemberAuthor

I rebased these changes on the latest upstream; comments that are related can be found on the logging PR related to introduction of an inheritance hierarchy and open() vs __init__ and potential fallibility.

The exceptions that are generated now are buried fairly deep which could be a bit challenging for users to work with. We max need to fix some stuff later on but I tried to document each of those potential exceptions explicitly so end-users know where they may need to dig to import appropriate exceptions.

Comment threadfastly_compute/config_store.py Outdated
Comment threadfastly_compute/config_store.py Outdated
@erikrose

Copy link
Copy Markdown
Member

The exceptions that are generated now are buried fairly deep which could be a bit challenging for users to work with.

I wrote up a proposal on that: #41.

@erikroseerikrose left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looks good! Let's get it in.

@posborne
posborne merged commit c4b16ee into mainFeb 17, 2026
3 checks passed
@posborne
posborne deleted the posborne/config-store branch February 17, 2026 21:13
Sign up for freeto 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.

3 participants

@posborne@dgohman-fastly@erikrose
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add ConfigStore support - #34

Merged
posborne merged 4 commits into
mainfrom
posborne/config-store
Feb 17, 2026
Merged

Add ConfigStore support#34
posborne merged 4 commits into
mainfrom
posborne/config-store

Conversation

@posborne

Copy link
Copy Markdown
Member

Mirroring the JS SDK, we provide a simple get() interface. I opted to not trying to provide a dict facade or similar. That is possible but it doesn't seem to represent a significant ergonomic improvement and might make it more likely that user's fail to keep in mind the potential exception behavior.

As with the Rust SDK, we intelligently use hint information from the host to get values with a big enough buffer if our original size is insufficient.


Potential discussion points:

  • I chose not to make the store look like a dict; this is possible but I don't feel it adds much and might be too lossy a mapping vs. just providing get/contains.
  • We don't have a strongly established resource pattern; here I take the approach of:
    • Context Manager + close
    • We do exit explicitly on the underlying resource rather than relying on the gc (if context manager or close() are used).
    • We don't try to provide an exception if use-after-close is performed, we document that the code will trap.

I expect to rework this code when the unified exception mapping is present, but feel there is enough here to review the important bits.

@erikroseerikrose left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

As much a note to myself as to you, but…

It looks like what this class adds (in addition to some very nice docs) is…

  1. Auto buffer sizing (yay)
  2. A close() method

Otherwise, the API looks parallel to what we'd get from the generated class, which would be…

fromwit_world.imports.config_storeimportStorewithStore.open("someConfig") asconfig:
print(config.get("someKey"), 1024) # and hope for the best bufferwise

See you in a few minutes! Oh, also, I'd prefer to subsume open() into __init__() so you can just ConfigStore("someStore").

@dgohman-fastly

Copy link
Copy Markdown
Contributor

As with the Rust SDK, we intelligently use hint information from the host to get values with a big enough buffer if our original size is insufficient.

The buffer len arguments are there for the benefit of the component adapter, which has to work with fixed-sized buffers passed in by the user code through the witx ABI. For code using WIT bindings directly, it's ok to just let the host call back into the guest with cabi_realloc with whatever length is needed. So the Python SDK here should be able to just pass the maximum u64 value to all the max-len arguments. That way it'll just never see buffer-len errors.

Mirroring the JS SDK, we provide a simple get() interface. I opted
to not trying to provide a dict facade or similar. That is possible
but it doesn't seem to represent a significant ergonomic improvement
and might make it more likely that user's fail to keep in mind the
potential exception behavior.
As with the Rust SDK, we intelligently use hint information from
the host to get values with a big enough buffer if our original
size is insufficient.
@posborne
posborneforce-pushed the posborne/config-store branch from 5bb9633 to e188cbaCompareFebruary 4, 2026 03:30
Also, use larger buffer size rather than doing
unecessary resizes and address a few other comments
from the PR.
@posborne
posborneforce-pushed the posborne/config-store branch from e188cba to e803f69CompareFebruary 4, 2026 03:34
@posborne

Copy link
Copy Markdown
MemberAuthor

I rebased these changes on the latest upstream; comments that are related can be found on the logging PR related to introduction of an inheritance hierarchy and open() vs __init__ and potential fallibility.

The exceptions that are generated now are buried fairly deep which could be a bit challenging for users to work with. We max need to fix some stuff later on but I tried to document each of those potential exceptions explicitly so end-users know where they may need to dig to import appropriate exceptions.

Comment threadfastly_compute/config_store.py Outdated
Comment threadfastly_compute/config_store.py Outdated
@erikrose

Copy link
Copy Markdown
Member

The exceptions that are generated now are buried fairly deep which could be a bit challenging for users to work with.

I wrote up a proposal on that: #41.

@erikroseerikrose left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looks good! Let's get it in.

@posborne
posborne merged commit c4b16ee into mainFeb 17, 2026
3 checks passed
@posborne
posborne deleted the posborne/config-store branch February 17, 2026 21:13
Sign up for freeto 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.

3 participants

@posborne@dgohman-fastly@erikrose
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Add ConfigStore support - #34

Merged
posborne merged 4 commits into
mainfrom
posborne/config-store
Feb 17, 2026
Merged

Add ConfigStore support#34
posborne merged 4 commits into
mainfrom
posborne/config-store

Conversation

@posborne

Copy link
Copy Markdown
Member

Mirroring the JS SDK, we provide a simple get() interface. I opted to not trying to provide a dict facade or similar. That is possible but it doesn't seem to represent a significant ergonomic improvement and might make it more likely that user's fail to keep in mind the potential exception behavior.

As with the Rust SDK, we intelligently use hint information from the host to get values with a big enough buffer if our original size is insufficient.


Potential discussion points:

  • I chose not to make the store look like a dict; this is possible but I don't feel it adds much and might be too lossy a mapping vs. just providing get/contains.
  • We don't have a strongly established resource pattern; here I take the approach of:
    • Context Manager + close
    • We do exit explicitly on the underlying resource rather than relying on the gc (if context manager or close() are used).
    • We don't try to provide an exception if use-after-close is performed, we document that the code will trap.

I expect to rework this code when the unified exception mapping is present, but feel there is enough here to review the important bits.

@erikroseerikrose left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

As much a note to myself as to you, but…

It looks like what this class adds (in addition to some very nice docs) is…

  1. Auto buffer sizing (yay)
  2. A close() method

Otherwise, the API looks parallel to what we'd get from the generated class, which would be…

fromwit_world.imports.config_storeimportStorewithStore.open("someConfig") asconfig:
print(config.get("someKey"), 1024) # and hope for the best bufferwise

See you in a few minutes! Oh, also, I'd prefer to subsume open() into __init__() so you can just ConfigStore("someStore").

@dgohman-fastly

Copy link
Copy Markdown
Contributor

As with the Rust SDK, we intelligently use hint information from the host to get values with a big enough buffer if our original size is insufficient.

The buffer len arguments are there for the benefit of the component adapter, which has to work with fixed-sized buffers passed in by the user code through the witx ABI. For code using WIT bindings directly, it's ok to just let the host call back into the guest with cabi_realloc with whatever length is needed. So the Python SDK here should be able to just pass the maximum u64 value to all the max-len arguments. That way it'll just never see buffer-len errors.

Mirroring the JS SDK, we provide a simple get() interface. I opted
to not trying to provide a dict facade or similar. That is possible
but it doesn't seem to represent a significant ergonomic improvement
and might make it more likely that user's fail to keep in mind the
potential exception behavior.
As with the Rust SDK, we intelligently use hint information from
the host to get values with a big enough buffer if our original
size is insufficient.
@posborne
posborneforce-pushed the posborne/config-store branch from 5bb9633 to e188cbaCompareFebruary 4, 2026 03:30
Also, use larger buffer size rather than doing
unecessary resizes and address a few other comments
from the PR.
@posborne
posborneforce-pushed the posborne/config-store branch from e188cba to e803f69CompareFebruary 4, 2026 03:34
@posborne

Copy link
Copy Markdown
MemberAuthor

I rebased these changes on the latest upstream; comments that are related can be found on the logging PR related to introduction of an inheritance hierarchy and open() vs __init__ and potential fallibility.

The exceptions that are generated now are buried fairly deep which could be a bit challenging for users to work with. We max need to fix some stuff later on but I tried to document each of those potential exceptions explicitly so end-users know where they may need to dig to import appropriate exceptions.

Comment threadfastly_compute/config_store.py Outdated
Comment threadfastly_compute/config_store.py Outdated
@erikrose

Copy link
Copy Markdown
Member

The exceptions that are generated now are buried fairly deep which could be a bit challenging for users to work with.

I wrote up a proposal on that: #41.

@erikroseerikrose left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looks good! Let's get it in.

@posborne
posborne merged commit c4b16ee into mainFeb 17, 2026
3 checks passed
@posborne
posborne deleted the posborne/config-store branch February 17, 2026 21:13
Sign up for freeto 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.

3 participants

@posborne@dgohman-fastly@erikrose