Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions docs/reference/oauth/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ <h2 class="section-title" id="header-submodules">Sub-modules</h2>
<dd>
<div class="desc"></div>
</dd>
<dt><code class="name"><a title="slack_sdk.oauth.sqlalchemy_utils" href="sqlalchemy_utils/index.html">slack_sdk.oauth.sqlalchemy_utils</a></code></dt>
<dd>
<div class="desc"></div>
</dd>
<dt><code class="name"><a title="slack_sdk.oauth.state_store" href="state_store/index.html">slack_sdk.oauth.state_store</a></code></dt>
<dd>
<div class="desc"><p>OAuth state parameter data store …</p></div>
Expand Down Expand Up @@ -865,6 +869,7 @@ <h3>Methods</h3>
<li><code><a title="slack_sdk.oauth.authorize_url_generator" href="authorize_url_generator/index.html">slack_sdk.oauth.authorize_url_generator</a></code></li>
<li><code><a title="slack_sdk.oauth.installation_store" href="installation_store/index.html">slack_sdk.oauth.installation_store</a></code></li>
<li><code><a title="slack_sdk.oauth.redirect_uri_page_renderer" href="redirect_uri_page_renderer/index.html">slack_sdk.oauth.redirect_uri_page_renderer</a></code></li>
<li><code><a title="slack_sdk.oauth.sqlalchemy_utils" href="sqlalchemy_utils/index.html">slack_sdk.oauth.sqlalchemy_utils</a></code></li>
<li><code><a title="slack_sdk.oauth.state_store" href="state_store/index.html">slack_sdk.oauth.state_store</a></code></li>
<li><code><a title="slack_sdk.oauth.state_utils" href="state_utils/index.html">slack_sdk.oauth.state_utils</a></code></li>
<li><code><a title="slack_sdk.oauth.token_rotation" href="token_rotation/index.html">slack_sdk.oauth.token_rotation</a></code></li>
Expand Down
10 changes: 10 additions & 0 deletions docs/reference/oauth/installation_store/sqlalchemy/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ <h2 class="section-title" id="header-classes">Classes</h2>
async with self.engine.begin() as conn:
i = installation.to_dict()
i[&#34;client_id&#34;] = self.client_id
i[&#34;installed_at&#34;] = normalize_datetime_for_db(i.get(&#34;installed_at&#34;))
i[&#34;bot_token_expires_at&#34;] = normalize_datetime_for_db(i.get(&#34;bot_token_expires_at&#34;))
i[&#34;user_token_expires_at&#34;] = normalize_datetime_for_db(i.get(&#34;user_token_expires_at&#34;))

i_column = self.installations.c
installations_rows = await conn.execute(
Expand Down Expand Up @@ -130,6 +133,8 @@ <h2 class="section-title" id="header-classes">Classes</h2>
# bots
b = bot.to_dict()
b[&#34;client_id&#34;] = self.client_id
b[&#34;installed_at&#34;] = normalize_datetime_for_db(b.get(&#34;installed_at&#34;))
b[&#34;bot_token_expires_at&#34;] = normalize_datetime_for_db(b.get(&#34;bot_token_expires_at&#34;))

b_column = self.bots.c
bots_rows = await conn.execute(
Expand Down Expand Up @@ -526,6 +531,9 @@ <h3>Inherited members</h3>
with self.engine.begin() as conn:
i = installation.to_dict()
i[&#34;client_id&#34;] = self.client_id
i[&#34;installed_at&#34;] = normalize_datetime_for_db(i.get(&#34;installed_at&#34;))
i[&#34;bot_token_expires_at&#34;] = normalize_datetime_for_db(i.get(&#34;bot_token_expires_at&#34;))
i[&#34;user_token_expires_at&#34;] = normalize_datetime_for_db(i.get(&#34;user_token_expires_at&#34;))

i_column = self.installations.c
installations_rows = conn.execute(
Expand Down Expand Up @@ -557,6 +565,8 @@ <h3>Inherited members</h3>
# bots
b = bot.to_dict()
b[&#34;client_id&#34;] = self.client_id
b[&#34;installed_at&#34;] = normalize_datetime_for_db(b.get(&#34;installed_at&#34;))
b[&#34;bot_token_expires_at&#34;] = normalize_datetime_for_db(b.get(&#34;bot_token_expires_at&#34;))

b_column = self.bots.c
bots_rows = conn.execute(
Expand Down
130 changes: 130 additions & 0 deletions docs/reference/oauth/sqlalchemy_utils/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
<meta name="generator" content="pdoc3 0.11.6">
<title>slack_sdk.oauth.sqlalchemy_utils API documentation</title>
<meta name="description" content="">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/typography.min.css" integrity="sha512-Y1DYSb995BAfxobCkKepB1BqJJTPrOp3zPL74AWFugHHmmdcvO+C48WLrUOlhGMc0QG7AE3f7gmvvcrmX2fDoA==" crossorigin>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css" crossorigin>
<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:1.5em;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:2em 0 .50em 0}h3{font-size:1.4em;margin:1.6em 0 .7em 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .2s ease-in-out}a:visited{color:#503}a:hover{color:#b62}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900;font-weight:bold}pre code{font-size:.8em;line-height:1.4em;padding:1em;display:block}code{background:#f3f3f3;font-family:"DejaVu Sans Mono",monospace;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source > summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible;min-width:max-content}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em 1em;margin:1em 0}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul ul{padding-left:1em}.toc > ul > li{margin-top:.5em}}</style>
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js" integrity="sha512-D9gUyxqja7hBtkWpPWGt9wfbfaMGVt9gnyCvYa+jojwwPHLCzUm5i8rpk7vD7wNee9bA35eYIjobYPaQuKS1MQ==" crossorigin></script>
<script>window.addEventListener('DOMContentLoaded', () => {
hljs.configure({languages: ['bash', 'css', 'diff', 'graphql', 'ini', 'javascript', 'json', 'plaintext', 'python', 'python-repl', 'rust', 'shell', 'sql', 'typescript', 'xml', 'yaml']});
hljs.highlightAll();
/* Collapse source docstrings */
setTimeout(() => {
[...document.querySelectorAll('.hljs.language-python > .hljs-string')]
.filter(el => el.innerHTML.length > 200 && ['"""', "'''"].includes(el.innerHTML.substring(0, 3)))
.forEach(el => {
let d = document.createElement('details');
d.classList.add('hljs-string');
d.innerHTML = '<summary>"""</summary>' + el.innerHTML.substring(3);
el.replaceWith(d);
});
}, 100);
})</script>
</head>
<body>
<main>
<article id="content">
<header>
<h1 class="title">Module <code>slack_sdk.oauth.sqlalchemy_utils</code></h1>
</header>
<section id="section-intro">
</section>
<section>
</section>
<section>
</section>
<section>
<h2 class="section-title" id="header-functions">Functions</h2>
<dl>
<dt id="slack_sdk.oauth.sqlalchemy_utils.normalize_datetime_for_db"><code class="name flex">
<span>def <span class="ident">normalize_datetime_for_db</span></span>(<span>dt: datetime.datetime | None) ‑> datetime.datetime | None</span>
</code></dt>
<dd>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def normalize_datetime_for_db(dt: Optional[datetime]) -&gt; Optional[datetime]:
&#34;&#34;&#34;
Normalize timezone-aware datetime to naive UTC datetime for database storage.

Ensures compatibility with existing databases using TIMESTAMP WITHOUT TIME ZONE.
SQLAlchemy DateTime columns without timezone=True create naive timestamp columns
in databases like PostgreSQL. This function strips timezone information from
timezone-aware datetimes (which are already in UTC) to enable safe comparisons.

Args:
dt: A timezone-aware or naive datetime object, or None

Returns:
A naive datetime in UTC, or None if input is None

Example:
&gt;&gt;&gt; from datetime import datetime, timezone
&gt;&gt;&gt; aware_dt = datetime(2024, 1, 1, 12, 0, 0, tzinfo=timezone.utc)
&gt;&gt;&gt; naive_dt = normalize_datetime_for_db(aware_dt)
&gt;&gt;&gt; naive_dt.tzinfo is None
True
&#34;&#34;&#34;
if dt is None:
return None
if dt.tzinfo is not None:
return dt.replace(tzinfo=None)
return dt</code></pre>
</details>
<div class="desc"><p>Normalize timezone-aware datetime to naive UTC datetime for database storage.</p>
<p>Ensures compatibility with existing databases using TIMESTAMP WITHOUT TIME ZONE.
SQLAlchemy DateTime columns without timezone=True create naive timestamp columns
in databases like PostgreSQL. This function strips timezone information from
timezone-aware datetimes (which are already in UTC) to enable safe comparisons.</p>
<h2 id="args">Args</h2>
<dl>
<dt><strong><code>dt</code></strong></dt>
<dd>A timezone-aware or naive datetime object, or None</dd>
</dl>
<h2 id="returns">Returns</h2>
<p>A naive datetime in UTC, or None if input is None</p>
<h2 id="example">Example</h2>
<pre><code class="language-python-repl">&gt;&gt;&gt; from datetime import datetime, timezone
&gt;&gt;&gt; aware_dt = datetime(2024, 1, 1, 12, 0, 0, tzinfo=timezone.utc)
&gt;&gt;&gt; naive_dt = normalize_datetime_for_db(aware_dt)
&gt;&gt;&gt; naive_dt.tzinfo is None
True
</code></pre></div>
</dd>
</dl>
</section>
<section>
</section>
</article>
<nav id="sidebar">
<div class="toc">
<ul></ul>
</div>
<ul id="index">
<li><h3>Super-module</h3>
<ul>
<li><code><a title="slack_sdk.oauth" href="../index.html">slack_sdk.oauth</a></code></li>
</ul>
</li>
<li><h3><a href="#header-functions">Functions</a></h3>
<ul class="">
<li><code><a title="slack_sdk.oauth.sqlalchemy_utils.normalize_datetime_for_db" href="#slack_sdk.oauth.sqlalchemy_utils.normalize_datetime_for_db">normalize_datetime_for_db</a></code></li>
</ul>
</li>
</ul>
</nav>
</main>
<footer id="footer">
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
</footer>
</body>
</html>
20 changes: 12 additions & 8 deletions docs/reference/oauth/state_store/sqlalchemy/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ <h2 class="section-title" id="header-classes">Classes</h2>

async def async_issue(self, *args, **kwargs) -&gt; str:
state: str = str(uuid4())
now = datetime.fromtimestamp(time.time() + self.expiration_seconds, tz=timezone.utc)
now = normalize_datetime_for_db(datetime.fromtimestamp(time.time() + self.expiration_seconds, tz=timezone.utc))
async with self.engine.begin() as conn:
await conn.execute(
self.oauth_states.insert(),
Expand All @@ -109,9 +109,10 @@ <h2 class="section-title" id="header-classes">Classes</h2>

async def async_consume(self, state: str) -&gt; bool:
try:
now = normalize_datetime_for_db(datetime.now(tz=timezone.utc))
async with self.engine.begin() as conn:
c = self.oauth_states.c
query = self.oauth_states.select().where(and_(c.state == state, c.expire_at &gt; datetime.now(tz=timezone.utc)))
query = self.oauth_states.select().where(and_(c.state == state, c.expire_at &gt; now))
result = await conn.execute(query)
for row in result.mappings():
self.logger.debug(f&#34;consume&#39;s query result: {row}&#34;)
Expand Down Expand Up @@ -189,9 +190,10 @@ <h3>Methods</h3>
</summary>
<pre><code class="python">async def async_consume(self, state: str) -&gt; bool:
try:
now = normalize_datetime_for_db(datetime.now(tz=timezone.utc))
async with self.engine.begin() as conn:
c = self.oauth_states.c
query = self.oauth_states.select().where(and_(c.state == state, c.expire_at &gt; datetime.now(tz=timezone.utc)))
query = self.oauth_states.select().where(and_(c.state == state, c.expire_at &gt; now))
result = await conn.execute(query)
for row in result.mappings():
self.logger.debug(f&#34;consume&#39;s query result: {row}&#34;)
Expand All @@ -215,7 +217,7 @@ <h3>Methods</h3>
</summary>
<pre><code class="python">async def async_issue(self, *args, **kwargs) -&gt; str:
state: str = str(uuid4())
now = datetime.fromtimestamp(time.time() + self.expiration_seconds, tz=timezone.utc)
now = normalize_datetime_for_db(datetime.fromtimestamp(time.time() + self.expiration_seconds, tz=timezone.utc))
async with self.engine.begin() as conn:
await conn.execute(
self.oauth_states.insert(),
Expand Down Expand Up @@ -293,7 +295,7 @@ <h3>Methods</h3>

def issue(self, *args, **kwargs) -&gt; str:
state: str = str(uuid4())
now = datetime.fromtimestamp(time.time() + self.expiration_seconds, tz=timezone.utc)
now = normalize_datetime_for_db(datetime.fromtimestamp(time.time() + self.expiration_seconds, tz=timezone.utc))
with self.engine.begin() as conn:
conn.execute(
self.oauth_states.insert(),
Expand All @@ -303,9 +305,10 @@ <h3>Methods</h3>

def consume(self, state: str) -&gt; bool:
try:
now = normalize_datetime_for_db(datetime.now(tz=timezone.utc))
with self.engine.begin() as conn:
c = self.oauth_states.c
query = self.oauth_states.select().where(and_(c.state == state, c.expire_at &gt; datetime.now(tz=timezone.utc)))
query = self.oauth_states.select().where(and_(c.state == state, c.expire_at &gt; now))
result = conn.execute(query)
for row in result.mappings():
self.logger.debug(f&#34;consume&#39;s query result: {row}&#34;)
Expand Down Expand Up @@ -383,9 +386,10 @@ <h3>Methods</h3>
</summary>
<pre><code class="python">def consume(self, state: str) -&gt; bool:
try:
now = normalize_datetime_for_db(datetime.now(tz=timezone.utc))
with self.engine.begin() as conn:
c = self.oauth_states.c
query = self.oauth_states.select().where(and_(c.state == state, c.expire_at &gt; datetime.now(tz=timezone.utc)))
query = self.oauth_states.select().where(and_(c.state == state, c.expire_at &gt; now))
result = conn.execute(query)
for row in result.mappings():
self.logger.debug(f&#34;consume&#39;s query result: {row}&#34;)
Expand Down Expand Up @@ -422,7 +426,7 @@ <h3>Methods</h3>
</summary>
<pre><code class="python">def issue(self, *args, **kwargs) -&gt; str:
state: str = str(uuid4())
now = datetime.fromtimestamp(time.time() + self.expiration_seconds, tz=timezone.utc)
now = normalize_datetime_for_db(datetime.fromtimestamp(time.time() + self.expiration_seconds, tz=timezone.utc))
with self.engine.begin() as conn:
conn.execute(
self.oauth_states.insert(),
Expand Down
2 changes: 1 addition & 1 deletion slack_sdk/version.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
"""Check the latest version at https://pypi.org/project/slack-sdk/"""

__version__ = "3.40.0"
__version__ = "3.40.1"