Skip to content

Conversation

@GuyKh
Copy link

@GuyKh GuyKh commented Aug 28, 2025

solves #80

@coderabbitai
Copy link

coderabbitai bot commented Aug 28, 2025

Walkthrough

Introduces NEEDS_APPLICATION_ID flags on auth adapter functions and updates init_auth to use config_factory(), resolve adapters from a mapping, consult getattr(adapter, "NEEDS_APPLICATION_ID", False) to decide whether to prompt for application_id, read client_secret via getpass, broaden device_auth signature, and remove config.store persistence.

Changes

Cohort / File(s) Summary
Auth initialization & prompting
trakt/auth/__init__.py
- Added NEEDS_APPLICATION_ID attributes: pin_auth=True, oauth_auth=False, device_auth=False.
- init_auth now builds config via config_factory(), resolves adapter from a methods mapping (defaulting to pin_auth), and uses getattr(adapter, "NEEDS_APPLICATION_ID", False) to decide whether to prompt for application_id.
- get_client_info prompts adjusted: client_secret read with getpass, application ID prompt/message formatting updated, and persistence via config.store() removed.
- device_auth signature changed to def device_auth(*args, config, **kwargs) to accept arbitrary args/kwargs.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant init_auth
  participant Adapter as Auth Adapter (pin/oauth/device)
  participant ConfigFactory as config_factory()
  participant Config as config
  participant Prompt as get_client_info
  Note over init_auth,ConfigFactory: init_auth constructs config via config_factory()
  User->>init_auth: Start authentication
  init_auth->>ConfigFactory: config = config_factory()
  init_auth->>Adapter: Resolve adapter from methods mapping (default pin_auth)
  init_auth->>Adapter: Read NEEDS_APPLICATION_ID via getattr(adapter, "NEEDS_APPLICATION_ID", False)
  alt NEEDS_APPLICATION_ID == True
    init_auth->>Config: Read application_id, client_id, client_secret
    init_auth->>Prompt: Prompt(app_id + client_id + client_secret) (client_secret via getpass)
  else NEEDS_APPLICATION_ID == False
    init_auth->>Config: Read client_id, client_secret
    init_auth->>Prompt: Prompt(client_id + client_secret) (client_secret via getpass)
  end
  Prompt-->>init_auth: Credentials
  init_auth->>Adapter: Call adapter with provided credentials
  Adapter-->>User: Auth result
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

I hop to the prompt with a twitch and a grin,
Some doors need an app, some let you stroll in.
Secrets are hidden, typed softly with care,
Flags guide the questions — neat, simple, and fair.
Thump-thump! says the rabbit, credentials in.

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbit in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbit in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbit gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbit read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbit help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbit ignore or @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbit summary or @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbit or @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
trakt/auth/__init__.py (3)

66-68: Bug: default branch returns a constant, not a callable.

methods.get(method, PIN_AUTH) falls back to the string/constant (e.g., "pin"), not the wrapper function. Use the function itself.

Apply:

-    adapter = methods.get(method, PIN_AUTH)
+    adapter = methods.get(method, pin_auth)

72-74: Harden against missing NEEDS_APPLICATION_ID on custom adapters.

If a downstream project supplies a different callable without this attribute, this will raise. Default to False.

Apply:

-        client_id, client_secret = get_client_info(adapter.NEEDS_APPLICATION_ID, config)
+        client_id, client_secret = get_client_info(getattr(adapter, "NEEDS_APPLICATION_ID", False), config)

33-49: Don’t echo secrets to the terminal.

Use getpass for the client secret input.

Apply:

-def get_client_info(app_id: bool, config: AuthConfig):
+def get_client_info(app_id: bool, config: AuthConfig):
+    from getpass import getpass
@@
-    client_secret = input('Please enter your client secret: ')
+    client_secret = getpass('Please enter your client secret: ')
🧹 Nitpick comments (1)
trakt/auth/__init__.py (1)

23-27: Unify wrapper signatures to avoid TypeError when kwargs are passed.

init_auth forwards *args, **kwargs. device_auth does not accept them, risking a TypeError if any are provided.

Apply:

-def device_auth(config):
+def device_auth(*args, config, **kwargs):
     from trakt.auth.device import DeviceAuthAdapter

-    return DeviceAuthAdapter(client=api(), config=config).authenticate()
+    return DeviceAuthAdapter(*args, client=api(), config=config, **kwargs).authenticate()
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between e879853 and ed36f3d.

📒 Files selected for processing (1)
  • trakt/auth/__init__.py (1 hunks)
🔇 Additional comments (1)
trakt/auth/__init__.py (1)

28-31: Good call: explicit NEEDS_APPLICATION_ID flags on wrappers.

Clear, localized signal for prompting behavior. This aligns with the PR goal.

@GuyKh
Copy link
Author

GuyKh commented Aug 28, 2025

Actually good advices here: #87 (review)

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
trakt/auth/__init__.py (1)

68-76: Fail fast on unknown auth method and load config before prompting.
Defaulting to PIN on unknown method can surprise callers; raise instead. Also ensure config is loaded before prompting.

-    config = config_factory()
-    adapter = methods.get(method, pin_auth)
+    config = config_factory()
+    config.load()
+    try:
+        adapter = methods[method]
+    except KeyError:
+        raise ValueError(
+            f"Unknown auth method: {method!r}. Expected one of: {', '.join(methods)}"
+        )
🧹 Nitpick comments (1)
trakt/auth/__init__.py (1)

25-28: Clarify that device_auth ignores extra args.
*args/**kwargs are accepted but unused; add a short docstring/comment to prevent misuse.

 def device_auth(*args, config, **kwargs):
     from trakt.auth.device import DeviceAuthAdapter
-
-    return DeviceAuthAdapter(client=api(), config=config).authenticate()
+    """Wrapper for DeviceAuthAdapter.authenticate(); *args/**kwargs are ignored."""
+    # For API symmetry with other auth wrappers; we intentionally ignore *args/**kwargs.
+    return DeviceAuthAdapter(client=api(), config=config).authenticate()
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between ed36f3d and e34d065.

📒 Files selected for processing (1)
  • trakt/auth/__init__.py (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
trakt/auth/__init__.py (3)
trakt/core.py (2)
  • config (73-83)
  • api (87-104)
trakt/auth/device.py (1)
  • DeviceAuthAdapter (10-115)
trakt/config.py (2)
  • AuthConfig (12-72)
  • store (66-72)
🔇 Additional comments (4)
trakt/auth/__init__.py (4)

4-6: Minor: Import and metadata update look good.
No action needed.


13-17: Unified wrapper signatures are consistent and explicit (keyword-only config).
Good use of keyword-only param for config and pass-through of *args/**kwargs.

Also applies to: 19-23


31-34: Good: NEEDS_APPLICATION_ID is explicit on wrappers.
This cleanly decouples prompting from adapter internals.


58-86: Verified init_auth usage and config.load behavior—no changes needed

Comment on lines +43 to 55
print(
"If you do not have a client ID and secret. Please visit the "
"following url to create them."
)
print("https://trakt.tv/oauth/applications")
client_id = input("Please enter your client id: ")
client_secret = getpass("Please enter your client secret: ")
if app_id:
msg = f'Please enter your application ID ({config.APPLICATION_ID}): '
msg = f"Please enter your application ID ({config.APPLICATION_ID}): "
user_input = input(msg)
if user_input:
config.APPLICATION_ID = user_input
return client_id, client_secret
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Make prompts resilient and reuse existing config values.
Allow pressing Enter to keep preloaded values; don’t force retyping secrets.

-    print(
-        "If you do not have a client ID and secret. Please visit the "
-        "following url to create them."
-    )
-    print("https://trakt.tv/oauth/applications")
-    client_id = input("Please enter your client id: ")
-    client_secret = getpass("Please enter your client secret: ")
+    print(
+        "If you do not have a client ID and secret. Please visit the "
+        "following url to create them."
+    )
+    print("https://trakt.tv/oauth/applications")
+    default_client_id = config.CLIENT_ID or ""
+    cid_prompt = "Please enter your client id"
+    if default_client_id:
+        cid_prompt += f" ({default_client_id})"
+    cid_prompt += ": "
+    client_id = input(cid_prompt) or default_client_id
+
+    secret_prompt = "Please enter your client secret (leave blank to keep existing): "
+    secret_input = getpass(secret_prompt)
+    client_secret = secret_input or (config.CLIENT_SECRET or "")
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
print(
"If you do not have a client ID and secret. Please visit the "
"following url to create them."
)
print("https://trakt.tv/oauth/applications")
client_id = input("Please enter your client id: ")
client_secret = getpass("Please enter your client secret: ")
if app_id:
msg = f'Please enter your application ID ({config.APPLICATION_ID}): '
msg = f"Please enter your application ID ({config.APPLICATION_ID}): "
user_input = input(msg)
if user_input:
config.APPLICATION_ID = user_input
return client_id, client_secret
print(
"If you do not have a client ID and secret. Please visit the "
"following url to create them."
)
print("https://trakt.tv/oauth/applications")
# Allow keeping existing client ID
default_client_id = config.CLIENT_ID or ""
cid_prompt = "Please enter your client id"
if default_client_id:
cid_prompt += f" ({default_client_id})"
cid_prompt += ": "
client_id = input(cid_prompt) or default_client_id
# Allow keeping existing client secret
secret_prompt = "Please enter your client secret (leave blank to keep existing): "
secret_input = getpass(secret_prompt)
client_secret = secret_input or (config.CLIENT_SECRET or "")
if app_id:
msg = f"Please enter your application ID ({config.APPLICATION_ID}): "
user_input = input(msg)
if user_input:
config.APPLICATION_ID = user_input
return client_id, client_secret
🤖 Prompt for AI Agents
In trakt/auth/__init__.py around lines 43 to 55, the interactive prompts always
force the user to retype values and expose no defaults; update prompts to
display existing config values as defaults and accept empty input (Enter) to
keep them: if config.CLIENT_ID or config.CLIENT_SECRET exist show them in the
prompt and when input is empty preserve the existing value (for secrets use
getpass but treat blank as “keep existing” without printing), and for
APPLICATION_ID keep the current config.APPLICATION_ID as the default and only
replace it if the user types a non-empty value; finally return the possibly
unchanged client_id and client_secret.

Comment on lines +58 to +60
def init_auth(
method: str, *args, client_id=None, client_secret=None, store=False, **kwargs
):
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Bug: store parameter is unused (functional regression).
Docstring advertises persistence via store, but there is no call to config.store(). Either implement persistence or remove the param/docs.

See proposed fix in Lines 86.

🤖 Prompt for AI Agents
In trakt/auth/__init__.py around lines 58-60, the init_auth function accepts a
store parameter but never persists the resulting config, causing a functional
regression; modify the function so that after the config is created/updated
(where config variable is available, e.g., after login/creation at the later
lines around 86), if store is True call config.store() (handle/propagate any
exceptions or log errors as appropriate) so the configuration is actually
persisted; alternatively, if persistence is intentionally removed, remove the
store parameter and update the docstring accordingly.

Comment on lines 80 to 84
if client_id is None and client_secret is None:
client_id, client_secret = get_client_info(adapter.NEEDS_APPLICATION_ID, config)
client_id, client_secret = get_client_info(
getattr(adapter, "NEEDS_APPLICATION_ID", False), config
)
config.CLIENT_ID, config.CLIENT_SECRET = client_id, client_secret
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Prompt when either client_id or client_secret is missing; keep provided values intact.
Currently prompts only when both are None; handle partial input.

-    if client_id is None and client_secret is None:
-        client_id, client_secret = get_client_info(
-            getattr(adapter, "NEEDS_APPLICATION_ID", False), config
-        )
+    if client_id is None or client_secret is None:
+        entered_id, entered_secret = get_client_info(
+            getattr(adapter, "NEEDS_APPLICATION_ID", False), config
+        )
+        client_id = client_id or entered_id
+        client_secret = client_secret or entered_secret
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if client_id is None and client_secret is None:
client_id, client_secret = get_client_info(adapter.NEEDS_APPLICATION_ID, config)
client_id, client_secret = get_client_info(
getattr(adapter, "NEEDS_APPLICATION_ID", False), config
)
config.CLIENT_ID, config.CLIENT_SECRET = client_id, client_secret
if client_id is None or client_secret is None:
entered_id, entered_secret = get_client_info(
getattr(adapter, "NEEDS_APPLICATION_ID", False), config
)
client_id = client_id or entered_id
client_secret = client_secret or entered_secret
config.CLIENT_ID, config.CLIENT_SECRET = client_id, client_secret
🤖 Prompt for AI Agents
In trakt/auth/__init__.py around lines 80 to 84, the code only prompts for
credentials when both client_id and client_secret are None; change it to prompt
when either is missing and preserve any provided value. Specifically, if
client_id is None or client_secret is None call get_client_info(getattr(adapter,
"NEEDS_APPLICATION_ID", False), config), then only overwrite the missing values
with the returned tuple (i.e., keep any non-None input intact), and finally
assign config.CLIENT_ID and config.CLIENT_SECRET from the merged values.

)
config.CLIENT_ID, config.CLIENT_SECRET = client_id, client_secret

adapter(*args, config=config, **kwargs)
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Return adapter result and persist when requested.
Preserve return value semantics and implement store=True.

-    adapter(*args, config=config, **kwargs)
+    result = adapter(*args, config=config, **kwargs)
+    if store:
+        config.store()
+    return result
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
adapter(*args, config=config, **kwargs)
result = adapter(*args, config=config, **kwargs)
if store:
config.store()
return result
🤖 Prompt for AI Agents
In trakt/auth/__init__.py around line 86, the adapter invocation currently
doesn't return its result nor handle persistence; change it to assign the
adapter call to a variable (result = adapter(*args, config=config, **kwargs)),
then if persistence is requested (e.g., config.get("store") is True or a store
flag in kwargs) call the configured persistence API to save the result (for
example invoke config.persist(result) or config["storage"].save(result)
depending on how config exposes storage), and finally return result so
return-value semantics are preserved.

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.

1 participant