Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nix flake #81

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open

nix flake #81

wants to merge 6 commits into from

Conversation

JJJHolscher
Copy link

@JJJHolscher JJJHolscher commented Oct 7, 2024

This pull request adds an additional way of calling Zotero2Readwise, but with no manual user installation required if they use nix.
You can already test it out with nix run github:jjjholscher/zotero2readwise.
The flake is made such that I don't expect it to require maintenance, since it uses poetry.lock to look up dependencies.

I'll explain the edits:

pyproject.toml
You use distutils, which as of python 3.12 is no longer included in the standard library, you need to include setuptools manually in the pyproject.toml if you want to continue relying on it.
I picked the version to match that of pyzotero, which seems to work.

For nix to recognize run.py as an entrypoint for the code, I had to add it under [tool.poetry.scripts]. I think this is general good practice, now poetry will recognize it and you can call it with poetry run run. (yes, that might be a bit confusing, I wasn't sure whether to name it zotero2readwise or main instead, such that you'd get poetry run zotero2readwise or poetry run main)

init.py
Your code always writes an error file to the package directory.
That's not possible in nix, so I had to include a check whether that users has write permissions there.
If not, the error file will be written to the working directory.

run.py and zt2rw.py
I assume not everyone will be glad that a nix run github:jjjholscher/zotero2readwise call will write a file to their working directory so I added a cli flag and a check to give the user the option for that not to happen in 102a46d
If you don't like that, you can go to 102a46d instead, which is a working version of this PR without that flag (don't mind the fact that the next commit mentions debugging, I merely neglected to refresh the flake.nix on my end, there was nothing wrong with the code)

maintenance burden

I don't expect there to be any for the next year, possibly there will literally never be any, especially if you don't change or update the code much.
Here are the two main scenarios where I envision scenarios where something should be manually updated:

If you ever choose to stop relying on run.py for the CLI entry, then the [tools.poetry.scripts] section in the pyproject.toml should reflect that.

If you ever update your dependencies and the dependencies use a new build system, the flake might complain about that. This should be very rare and be easily fixable. If you are curious you can see that I had to add

        overrides = defaultPoetryOverrides.extend (final: prev: {
          pyzotero = prev.pyzotero.overridePythonAttrs ( old: {
            buildInputs = (old.buildInputs or [ ]) ++ [ prev.setuptools ];
          });
        });

to the flake, which is how such problems tend to be resolvable. Feel free to contact me if this happens and you don't want to burden yourself with that (I don't expect it to happen).

should you trust me?

I don't have much experience writing nix flakes.
Overal flakes are made to require little maintenance, and have no changing behavior if the lock files remain the same.
People can even invoke past versions of flakes, by supplying a git commit, in case HEAD stops working.
But, I understand if you don't want to include technology in your git repo that you yourself don't understand (if that's the case), in which case I'll just keep my fork alive (and maybe you could mention its existence in the readme, such that nix users know they might be able to use it).

Summary by CodeRabbit

  • New Features

    • Introduced a new usage approach for the zotero2readwise library using Nix, allowing users to run the library without installation.
    • Added a command-line option to suppress the creation of a report file for failed highlights.
    • Updated the run script to encapsulate logic in a main() function and added an option to suppress writing failed annotations.
  • Bug Fixes

    • Enhanced logic to determine the directory for storing failed Zotero items based on write permissions.
  • Documentation

    • Updated README.md to include new usage instructions and command format for the Nix approach.
  • Chores

    • Updated project version and added necessary dependencies in pyproject.toml.

Copy link

coderabbitai bot commented Oct 7, 2024

Walkthrough

The pull request introduces several updates to the zotero2readwise library. A new flake.nix file is added to facilitate running the library through Nix, allowing users to execute commands without installation. The README.md is updated to include this new approach and relevant command details. Additionally, the pyproject.toml file is modified to update the project version and add a new dependency. Changes to the code include updates to the handling of failed items, encapsulation of the main script logic, and the introduction of a parameter to control the saving of failed items.

Changes

File Change Summary
README.md Added "Approach 3" for using zotero2readwise via Nix; included command format and output file handling notes.
flake.nix New file for Nix flake configuration; defines dependencies and application entry point for zotero2readwise.
pyproject.toml Updated version to "0.4.5"; added setuptools dependency; defined a new script for run.
zotero2readwise/__init__.py Updated FAILED_ITEMS_DIR logic based on write permissions of TOP_DIR.
zotero2readwise/run.py Refactored to use a main() function; added --suppress_failures argument for controlling output of failures.
zotero2readwise/zt2rw.py Introduced write_failures parameter to Zotero2Readwise class; modified logic for saving failed items.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Nix
    participant Zotero2Readwise

    User->>Nix: Execute command to run zotero2readwise
    Nix->>Zotero2Readwise: Start application
    Zotero2Readwise->>Zotero2Readwise: Check TOP_DIR writable
    alt TOP_DIR writable
        Zotero2Readwise->>Zotero2Readwise: Set FAILED_ITEMS_DIR to TOP_DIR
    else TOP_DIR not writable
        Zotero2Readwise->>Zotero2Readwise: Set FAILED_ITEMS_DIR to current working directory
    end
    Zotero2Readwise->>Zotero2Readwise: Process Zotero items
    alt --suppress_failures not set
        Zotero2Readwise->>Zotero2Readwise: Write failed items to JSON
    else --suppress_failures set
        Zotero2Readwise->>Zotero2Readwise: Do not write failed items
    end
    Zotero2Readwise->>User: Return results
Loading

🐰 "In a world of Nix and Zotero's might,
A new approach brings joy and light.
With failures tucked away with care,
Our rabbit hops without a scare.
So gather 'round, let's celebrate,
For changes made, oh, isn't it great!" 🐇


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ 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.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai 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:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @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

Documentation and Community

  • 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: 2

🧹 Outside diff range and nitpick comments (11)
zotero2readwise/__init__.py (1)

1-10: LGTM! Consider minor improvements for clarity and user feedback.

The changes effectively address the issue of write permissions in read-only environments, which aligns well with the PR objectives. The implementation is correct and the added comments explain the purpose of the change.

Consider the following minor improvements:

  1. Make the comment more specific about which file is being written:
- # If TOP_DIR is readonly os with nix,
- # then failed_zotero_items.json is written to the working directory instead.
+ # If TOP_DIR is read-only (e.g., when using Nix),
+ # then the failed_zotero_items.json file is written to the working directory instead.
  1. Add a log or print statement to inform the user when the fallback directory is used:
import logging

# ... existing code ...

FAILED_ITEMS_DIR = TOP_DIR if os.access(TOP_DIR, os.W_OK) else Path.cwd()
if FAILED_ITEMS_DIR != TOP_DIR:
    logging.warning(f"Write access denied to {TOP_DIR}. Using {FAILED_ITEMS_DIR} for failed items instead.")

These changes would enhance clarity and provide better feedback to users.

flake.nix (2)

1-4: LGTM! Consider pinning nixpkgs version for stability.

The flake description and inputs are well-defined. However, for improved stability, consider pinning the nixpkgs to a specific commit or tag instead of using the unstable channel.

Example of pinning nixpkgs:

inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.05";

11-20: LGTM! Consider extracting the pyzotero override for better maintainability.

The zotero2readwise application definition is correct and well-structured. The override for pyzotero is necessary and properly documented.

To improve maintainability, consider extracting the pyzotero override into a separate function:

let
  pyzoteroOverride = prev: {
    pyzotero = prev.pyzotero.overridePythonAttrs (old: {
      buildInputs = (old.buildInputs or [ ]) ++ [ prev.setuptools ];
    });
  };

  customOverrides = defaultPoetryOverrides.extend (final: prev: 
    pyzoteroOverride prev
  );

  zotero2readwise = mkPoetryApplication {
    projectDir = ./.;
    overrides = customOverrides;
  };
in

This change will make it easier to add more overrides in the future if needed.

pyproject.toml (3)

41-41: LGTM! Consider specifying Python version compatibility.

The addition of setuptools as a dependency is appropriate, especially for Python 3.12 compatibility. Good job on including this with a suitable version constraint.

Consider updating the python dependency in [tool.poetry.dependencies] to reflect compatibility with Python 3.12, e.g., python = "^3.8,<3.13". This would make the Python version requirements more explicit and align with the setuptools addition.


48-50: LGTM! Consider a more specific script name.

The addition of the script entry point is good and aligns with the PR objectives. This will allow users to easily run the main function using Poetry.

Consider using a more specific name for the script, such as zotero2readwise or z2r, instead of run. This would make the command more intuitive and avoid the repetition when using poetry run run. For example:

[tool.poetry.scripts]
zotero2readwise = "zotero2readwise.run:main"

This would allow users to run the script with poetry run zotero2readwise.


Line range hint 1-85: Consider updating Python version classifiers

The file looks good overall, with appropriate updates to the version and necessary changes for Python 3.12 compatibility.

Consider updating the classifiers section to include Python 3.12 compatibility. Currently, it only mentions Python 3.8. You could add:

classifiers = [
    # ... existing classifiers ...
    "Programming Language :: Python :: 3.8",
    "Programming Language :: Python :: 3.9",
    "Programming Language :: Python :: 3.10",
    "Programming Language :: Python :: 3.11",
    "Programming Language :: Python :: 3.12",
    # ... other classifiers ...
]

This would provide more accurate information about the project's Python version compatibility.

zotero2readwise/run.py (2)

50-54: Approved: New CLI flag for suppressing failure reports

The addition of the --suppress_failures flag is a good feature, allowing users to control whether failed annotations are written to a report file. This aligns well with the PR objectives.

Consider renaming this flag to --suppress_failure_report for better clarity and consistency with the existing naming conventions in the script.


76-77: Approved: Updated Zotero2Readwise instantiation

The changes to the Zotero2Readwise instantiation correctly implement the new functionality:

  1. The 'since' parameter is properly set based on the --use_since flag.
  2. The 'write_failures' parameter is correctly set as the negation of --suppress_failures.

These updates align well with the PR objectives and the new CLI flag.

Consider renaming the write_failures parameter to write_failure_report for consistency with the suggested CLI flag name change.

zotero2readwise/zt2rw.py (3)

20-21: LGTM! Consider adding a docstring for the new parameter.

The addition of the write_failures parameter is a good improvement, allowing users to control whether failed items are written to a file. The default value of True maintains backward compatibility.

Consider adding a brief description of the write_failures parameter in the method's docstring to improve documentation.


59-60: LGTM! Consider a minor refactoring for improved readability.

The updated condition correctly implements the write_failures option, ensuring that failed items are only saved if the user has opted to do so and there are actually failed items to save.

Consider refactoring the condition for improved readability:

if self.write_failures and self.zotero.failed_items:
    self.zotero.save_failed_items_to_json("failed_zotero_items.json")

This change makes the condition more concise and easier to read at a glance.


Line range hint 20-60: Summary: New write_failures option successfully implemented

The changes in this file successfully implement the new write_failures option, allowing users to control whether failed Zotero items are saved to a JSON file. The implementation is consistent across the __init__ and run methods, and maintains backward compatibility with the default value of True.

Key points:

  1. New parameter added to __init__ method
  2. New instance variable self.write_failures initialized
  3. Updated condition in run method to use the new option

These changes align well with the PR objectives and improve the flexibility of the library for users who may not want to save failed items.

Consider adding a configuration option or environment variable to allow users to specify the filename for failed items, instead of hardcoding "failed_zotero_items.json". This would provide even more flexibility for users with specific naming conventions or file organization needs.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 261ac3a and 5bc76aa.

⛔ Files ignored due to path filters (1)
  • flake.lock is excluded by !**/*.lock
📒 Files selected for processing (6)
  • README.md (1 hunks)
  • flake.nix (1 hunks)
  • pyproject.toml (1 hunks)
  • zotero2readwise/init.py (1 hunks)
  • zotero2readwise/run.py (3 hunks)
  • zotero2readwise/zt2rw.py (4 hunks)
🧰 Additional context used
🪛 LanguageTool
README.md

[uncategorized] ~84-~84: “you” seems less likely than “your” (belonging to you).
Context: ...ckage directory, will now be written to you working directory, since nix does not a...

(AI_HYDRA_LEO_CP_YOU_YOUR)

🔇 Additional comments (8)
flake.nix (2)

1-30: Overall, the flake looks good with room for some enhancements.

The flake.nix file successfully defines a Nix flake for running the zotero2readwise script. It correctly sets up the necessary inputs, defines the zotero2readwise application using poetry2nix, and creates an app that can be run using nix run.

Main points for improvement:

  1. Enhance cross-platform compatibility by supporting multiple systems.
  2. Consider pinning the nixpkgs version for improved stability.
  3. Extract the pyzotero override for better maintainability.
  4. Update or remove the outdated comment in the app definition.

These changes will make the flake more robust, maintainable, and widely usable across different systems.


22-28: Update or remove the outdated comment and verify the script name.

The app definition looks correct. However, there's an outdated comment that needs attention.

  1. Remove or update the comment on line 25 as it refers to replacing <script>, which is not applicable in the current code.
  2. Verify that "run" is indeed the correct script name defined in the [tool.poetry.scripts] section of your pyproject.toml file.

To verify the script name, you can run the following command:

Make sure the output contains a line like run = "zotero2readwise.__main__:main" or similar, confirming that "run" is the correct script name.

✅ Verification successful

Remove the outdated comment and confirm the script name is correct.

The app definition is accurate, and the script name "run" matches the [tool.poetry.scripts] section in your pyproject.toml file. Please remove the outdated comment to prevent any confusion.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

grep -A 5 '\[tool.poetry.scripts\]' pyproject.toml

Length of output: 199

zotero2readwise/run.py (3)

8-8: Excellent refactoring: Introduced main() function

Encapsulating the main logic in a main() function is a great improvement. It enhances modularity, makes the code more testable, and follows the best practices for structuring Python scripts.


83-84: Approved: Proper script execution setup

The addition of the if __name__ == "__main__": block calling the main() function is a standard and recommended Python practice. This setup allows the script to be both imported as a module and run directly, enhancing its versatility and maintainability.


Line range hint 1-84: Overall assessment: Well-structured and functional improvements

The changes in this file significantly improve the script's structure and functionality:

  1. The introduction of the main() function enhances modularity and testability.
  2. The new --suppress_failures flag provides users with more control over error reporting.
  3. The updated Zotero2Readwise instantiation correctly implements the new functionality.
  4. The script execution setup follows best practices for Python scripts.

These changes align well with the PR objectives, introducing the ability to control failure reporting and implement the 'since' functionality. The code is clean, well-structured, and maintains good practices throughout.

Consider the minor naming suggestions for consistency, but these are not critical for the functionality of the script.

zotero2readwise/zt2rw.py (1)

33-33: LGTM! Consistent with the method signature update.

The new instance variable self.write_failures is correctly initialized with the value of the write_failures parameter. This change is consistent with the method signature update and allows the write_failures option to be used in other methods of the class.

README.md (2)

85-85: Approve addition of suppress_failures option.

The introduction of the --suppress_failures option is a valuable addition. It provides users with more control over the output and is clearly explained.


78-86: Approve overall integration of new content.

The new "Approach 3" section is well-integrated into the existing documentation. Its placement at the end of the usage instructions is logical, and the consistent numbering (Approach 3) maintains the document's structure. The blank line separation helps to distinguish it from the previous approaches, enhancing readability.

🧰 Tools
🪛 LanguageTool

[uncategorized] ~84-~84: “you” seems less likely than “your” (belonging to you).
Context: ...ckage directory, will now be written to you working directory, since nix does not a...

(AI_HYDRA_LEO_CP_YOU_YOUR)

Comment on lines +6 to +10
outputs = { self, nixpkgs, poetry2nix }:
let
system = "x86_64-linux";
pkgs = nixpkgs.legacyPackages.${system};
inherit (poetry2nix.lib.mkPoetry2Nix { inherit pkgs; }) mkPoetryApplication defaultPoetryOverrides;
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Enhance cross-platform compatibility.

The current implementation hardcodes the system to "x86_64-linux". To improve cross-platform compatibility, consider using a more flexible approach.

Replace the hardcoded system with a dynamic approach:

outputs = { self, nixpkgs, poetry2nix }:
  let
    supportedSystems = [ "x86_64-linux" "x86_64-darwin" "aarch64-linux" "aarch64-darwin" ];
    forAllSystems = nixpkgs.lib.genAttrs supportedSystems;
    pkgs = forAllSystems (system: nixpkgs.legacyPackages.${system});
  in
  {
    apps = forAllSystems (system: {
      default = {
        type = "app";
        program = "${self.packages.${system}.default}/bin/run";
      };
    });
    
    packages = forAllSystems (system: {
      default = let
        inherit (poetry2nix.lib.mkPoetry2Nix { inherit (pkgs.${system}) pkgs; }) mkPoetryApplication defaultPoetryOverrides;
      in
        mkPoetryApplication {
          # ... rest of your mkPoetryApplication configuration
        };
    });
  };

This change will allow the flake to work on multiple architectures and operating systems.

Comment on lines +79 to +85
## Approach 3 (through the nix flake)
If you have `nix`, you can skip any installation and do:
```sh
nix run github:e-alizadeh/Zotero2Readwise -- <readwise_token> <zotero_key> <zotero_id>
```
The text file with failed highlights, which usually would be written to the Zotero2Readwise python package directory, will now be written to you working directory, since nix does not allow writing to package directories.
If you don't want this file created, supply `--suppress_failures` as an additional argument.
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Approve new "Approach 3" section with minor correction.

The new section effectively introduces the Nix flake approach, aligning with the PR objectives. The command format is clear, and the note about the output file location is valuable for users.

However, there's a minor grammatical error that should be corrected:

In line 84, "you working directory" should be "your working directory".

Please apply this change:

-The text file with failed highlights, which usually would be written to the Zotero2Readwise python package directory, will now be written to you working directory, since nix does not allow writing to package directories.
+The text file with failed highlights, which usually would be written to the Zotero2Readwise python package directory, will now be written to your working directory, since nix does not allow writing to package directories.
📝 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
## Approach 3 (through the nix flake)
If you have `nix`, you can skip any installation and do:
```sh
nix run github:e-alizadeh/Zotero2Readwise -- <readwise_token> <zotero_key> <zotero_id>
```
The text file with failed highlights, which usually would be written to the Zotero2Readwise python package directory, will now be written to you working directory, since nix does not allow writing to package directories.
If you don't want this file created, supply `--suppress_failures` as an additional argument.
## Approach 3 (through the nix flake)
If you have `nix`, you can skip any installation and do:
```sh
nix run github:e-alizadeh/Zotero2Readwise -- <readwise_token> <zotero_key> <zotero_id>
```
The text file with failed highlights, which usually would be written to the Zotero2Readwise python package directory, will now be written to your working directory, since nix does not allow writing to package directories.
If you don't want this file created, supply `--suppress_failures` as an additional argument.
🧰 Tools
🪛 LanguageTool

[uncategorized] ~84-~84: “you” seems less likely than “your” (belonging to you).
Context: ...ckage directory, will now be written to you working directory, since nix does not a...

(AI_HYDRA_LEO_CP_YOU_YOUR)

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