Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    Running commanline application with Python

    General Talk
    2023 python macos windows
    2
    15
    3.0k
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • P
      Peek
      last edited by

      Hi guys,

      Running into a bit of an issue with the commandline application on Windows/MacOS when running and "driving" it via Python (standalone, outside Cinema4D).

      We're writing an application that automatically handles the license logins on the machines in our renderfarms. Every time there is a minor update to Cinema or the Maxon App, all our machines seem to lose their license which is a lot of manual labor to get working again.

      We have the following code:

      import subprocess
      import os
      from os.path import expanduser
      import time
      
      # Petermine the platform (Windows or MacOS)
      is_windows = os.name == 'nt'
      
      # Path to your C4D executable
      if is_windows:
          try:
              c4d_executable = r'C:\Program Files\Maxon Cinema 4D 2023\Commandline.exe'
          except:
              print("Commandline executablecould not be found!")
              subprocess.wait(5)
      else:
          try:
              c4d_executable = '/Applications/Maxon Cinema 4D 2023/Commandline.app/Contents/MacOS/Commandline'
          except:
              print("Commandline executablecould not be found!")
              subprocess.wait(5)
      
      
      # Define the license information to provide
      license_method = "2"
      license_username = "XXXXXXXX"
      license_password = "XXXXXXXX"
      license_floating_commandline = '1'
      
      # Define license files
      
      
      # Get user home directory
      home = expanduser("~")
      print(home)
      
      
      # Create a subprocess to run C4D
      c4d_process = subprocess.Popen(
          [c4d_executable],
          stdin=subprocess.PIPE,
          stdout=subprocess.PIPE,
          stderr=subprocess.PIPE,
          shell=True,
          text=True
      )
      
      # Use a loop to read and print the output in real-time
      def capture_and_print_output(process):
          while True:
              output_line = process.stdout.readline()
              if not output_line:
                  break  # No more output, exit the loop
              print(output_line, end='')  # Print the line without adding extra newline
      
              # Check for error messages in the output
              if "Error:" in output_line:
                  print("Error message detected:", output_line)
      
          while True:
              error_line = process.stderr.readline()
              if not error_line:
                  break  # No more error output, exit the loop
              print("Error:", error_line, end='')
      
      # Capture and print outputs before providing license information
      capture_and_print_output(c4d_process)  # Output before license input
      
      # Wait for Commandline to prompt for input
      output, _ = c4d_process.communicate(timeout=10)
      
      print("Output:", output)
      
      if "Please select:" in output:
          print("Inside the license method loop")
          # Provide the license information
          time.sleep(5)
          c4d_process.stdin.write(license_method + '\n')
          c4d_process.stdin.flush()
      
          print("sleeping")
          time.sleep(2)
      
          # Capture and print outputs after providing license method
          capture_and_print_output(c4d_process)
      
          # Send the Enter key
          c4d_process.stdin.write('\n')
          c4d_process.stdin.flush()
      
          print("sleeping after Enter")
          time.sleep(2)
      
          # Capture and print outputs after providing license method
          capture_and_print_output(c4d_process)
          
          time.sleep(2)
          
      
          # Capture and print outputs after providing license method
          capture_and_print_output(c4d_process)
      
      if "Account email address []: " in output:
          print("Inside the email address loop")
          # Provide the license information
          c4d_process.stdin.write(license_username)
          c4d_process.stdin.flush()
      
          # Send the Enter key
          c4d_process.stdin.write('\n')
          c4d_process.stdin.flush()
      
          # Capture and print outputs after providing email address
          capture_and_print_output(c4d_process)
      
      if "Password: " in output:
          print("Inside the password loop")
          # Provide the license information
          c4d_process.stdin.write(license_password)
          c4d_process.stdin.flush()
      
          # Send the Enter key
          c4d_process.stdin.write('\n')
          c4d_process.stdin.flush()
      
          # Capture and print outputs after providing password
          capture_and_print_output(c4d_process)
      
      if "Please choose one of the following options: " in output:
          print("Inside the license type loop")
          # Provide type of license
          c4d_process.stdin.write(license_floating_commandline)
          c4d_process.stdin.flush()
      
          # Send the Enter key
          c4d_process.stdin.write('\n')
          c4d_process.stdin.flush()
      
          # Capture and print outputs after providing license type
          capture_and_print_output(c4d_process)
      
      else:
          print("No input detected!")
          c4d_process.wait(5)
          c4d_process.stdin.close()
          c4d_process.stdout.close()
          c4d_process.stderr.close()
          c4d_process.terminate()
      
      # You can now continue working with the C4D process or wait for it to finish
      print("Licensing process ran succesfully")
      c4d_process.wait(5)
      
      # Close the subprocess and clean up
      c4d_process.stdin.close()
      c4d_process.stdout.close()
      c4d_process.stderr.close()
      c4d_process.terminate()
      

      Basically what happens is that the commandline application doesn't seem to register the "replies" that Python gives it when it asks for specific license information inputs. I've tried a ton of different ways to go about it but none seem to work.
      Tried with sleep, without sleep, "Please select: ", "Please select:", "Enter the license method:", "Enter the license method: ", with \n, without \n etc.

      Is there some specific timing I need to adhere to or something else behind the scenes that I'm not aware of?

      Kind regards

      ferdinandF 1 Reply Last reply Reply Quote 0
      • ferdinandF
        ferdinand @Peek
        last edited by ferdinand

        Hello @Peek,

        Thank you for reaching out to us. I will answer here within this week, but I must deliberate with my colleagues first, as I am unsure about both legal and technical aspects of what you are trying to do here.

        Cheers,
        Ferdinand

        MAXON SDK Specialist
        developers.maxon.net

        P 1 Reply Last reply Reply Quote 0
        • P
          Peek @ferdinand
          last edited by Peek

          @ferdinand : Hi Ferdinand, thanks for getting back to me on this.

          As for the legal aspects (the following is my personal opinion), what do you mean exactly?
          We pay for licenses and we don't want the inconvenience of having to manually go through all render clients when the licensing system fails us yet again.
          These actions (inputting license information on all commandline clients in our farm) cost man hours which can be more effectively spent working for clients rather than working around a needlessly cumbersome system.
          There is no effective difference between me manually inputting the information on a client and doing it in an automated fashion with a piece of code.

          That being said, if I'm missing something else here please feel free to correct my thinking.

          Cheers,
          Joep

          ferdinandF 1 Reply Last reply Reply Quote 0
          • ferdinandF
            ferdinand @Peek
            last edited by

            Hello @Peek,

            I understand your motivation and it is understandable. The legal aspect is not about you owning the licenses or not. For further details, I would still have to ask you to wait until I have talked with my colleagues.

            Cheers,
            Ferdinand

            MAXON SDK Specialist
            developers.maxon.net

            P 1 Reply Last reply Reply Quote 0
            • P
              Peek @ferdinand
              last edited by

              @ferdinand : I will, thanks again for investigating ๐Ÿ™‚

              Cheers,
              Joep

              ferdinandF 1 Reply Last reply Reply Quote 0
              • ferdinandF
                ferdinand @Peek
                last edited by ferdinand

                Hey @Peek,

                so, after some digging, here is how you can do this.

                1. In general, we cannot support interacting with our logins by emulating user inputs.
                2. But you can use the command line arguments which are documented here and in more detail here.
                3. There is/was a missing puzzle piece to all this in form of g_licenseModel, which before has been a private argument and therefore cannot be found in the technical SDK documentation I linked to above or the command line user documentation. I have documented the argument below, and we will also expose it in the technical and user documentation (in fact a few things should be updated there).

                Note: This thread was unrelated to the Cinema 4D SDK (and therefore technically out of scope of support). Please post such questions in General Talk in the future. I have moved this thread. And while it is understandable that you were seeking support in this case, the SDK group cannot provide support for generic pipelining issues. You should reach out to end user support for them.

                Cheers,
                Ferdinand

                Code:

                """Demonstrates how to login into any Cinema 4D application (Cinema 4D, c4dpy, commandline, 
                Team Render) using command line arguments.
                """
                
                import os
                import subprocess
                
                def run_c4d(
                        appPath: str, filePath: str, args: tuple[str] = ()) -> subprocess.CompletedProcess:
                    """Runs a Cinema 4D app at the given #appPath with the given command line #args.
                
                    Optionally one can pass a #filePath to load a file into the app (*.c4d, *.py, *.bmp, etc.).
                    """
                    if not os.path.exists(appPath) or not os.path.isfile(appPath):
                        raise OSError(f"The path '{appPath = }' does not exist or is not a file.")
                    if filePath != "" and (not os.path.exists(filePath) or not os.path.isfile(filePath)):
                        raise OSError(f"The path '{filePath = }' does not exist or is not a file.")
                    
                    return subprocess.run([appPath, filePath] + list(args))
                
                def main() -> None:
                    """Runs the example.
                    """
                    # Some example apps to run.
                    cmdlineApp: str = "c:\\program files\\maxon\\2023.2.2\\commandline.exe"
                    c4dpyApp: str = "c:\\program files\\maxon\\2023.2.2\\c4dpy.exe"
                
                    # Provide our credentials for a Maxon Account login. This only works with non-federated accounts,
                    # i.e., logins that are not forwarded to Apple, Google, or Facebook. Note that Maxon Account as 
                    # a login model has been deprecated in 2024. In the GUI of the Cinema 4D license manager it has
                    # been removed altogether, in the terminal it is still available.
                    userLogin: list[str] = [
                        # The license model we are using.
                        # Other values for LICENSEMODEL:
                        #   ::LICENSESERVER - Maxon License Server
                        #   ::RLM           - RLM License Server
                        #   ::MAXONAPP      - Maxon App
                        "g_licenseModel=LICENSEMODEL::MAXONACCOUNT",
                        # The credentials.
                        "[email protected]", 
                        "g_licensePassword=password1234"
                    ]
                
                    # Run the commandline app.
                    res: subprocess.CompletedProcess = run_c4d(
                        cmdlineApp, "", userLogin)
                    if (res.stderr):
                        raise RuntimeError(f"Terminated on process error: {res.stderr}")
                
                    # Run the c4dpy app.
                    res: subprocess.CompletedProcess = run_c4d(
                        c4dpyApp, "c:\\users\\f_hoppe\\desktop\\my_script.py", userLogin)
                    if (res.stderr):
                        raise RuntimeError(f"Terminated on process error: {res.stderr}")
                
                    
                if __name__ == "__main__":
                    main()
                

                MAXON SDK Specialist
                developers.maxon.net

                1 Reply Last reply Reply Quote 1
                • ferdinandF ferdinand moved this topic from Cinema 4D SDK on
                • P
                  Peek
                  last edited by

                  Hi @ferdinand : Thanks a ton for helping out even though technically this kind of support is outside the scope.

                  I will read up on the material you provided and implement the code example into our own code.

                  As always you've been very helpful ๐Ÿ™‚

                  Cheers,

                  Joep

                  1 Reply Last reply Reply Quote 0
                  • P
                    Peek
                    last edited by

                    @ferdinand Due to the busy schedule at work I've only now gotten around to getting to implement this and I'm a bit stuck.

                    • When I run both the commandline and c4dpy the terminal goes into some kind of endless loop on one of the MacOS rendernodes, it just keeps going endlessly with the same wall of text.
                    • When I run just the commandline part it ends, but the license info doesn't seem to be inputted. As when I then manually run the commandline afterwards it asks for license info again.
                    • When I run just the c4dpy part it also goes into an endless loop spouting the same wall of text over and over again.

                    You mentioned in your reply "and we will also expose it in the technical and user documentation (in fact a few things should be updated there)." but I can't find anything in the SDK documentation about "g_license", just one quick mention in c4dpy about passing username and password as arguments.

                    ferdinandF 1 Reply Last reply Reply Quote 0
                    • ferdinandF
                      ferdinand @Peek
                      last edited by ferdinand

                      Hello @Peek,

                      Regarding the docs, I simply forgot to add stuff on the SDK side. Thank you for the hint, I will add it now.

                      Regarding your problems with logging in: My script just automates some shell commands and there is no difference between the apps (c4d, cmdline, c4dpy, t-server, t-client) regarding login, when it works with one, it will work with all. I just tested my script, and for me it still works with 2023.2.2 and also in 2024.2.0. Here I ran c4dpy with a script printing Hello World!:

                      3f466755-639e-459d-ad69-d6b6eff0c035-image.png

                      To get a better sense of what is going wrong, just run the following command in the shell of your choice after filling in your data:

                      [PATH] g_licenseModel=LICENSEMODEL::MAXONACCOUNT g_licenseUsername=[HANDLE] g_licensePassword=[PASSWORD]
                      
                      e.g.,
                      c:\"program files"\maxon\2024.2.0\commandline.exe g_licenseModel=LICENSEMODEL::MAXONACCOUNT [email protected] g_licensePassword=MyFancyPassword
                      

                      When your login fails (wall of text), it either means your credentials are invalid or that you have a federated login. A federated login is any login that redirects you away from our id.maxon.net plugin page to a third party page to fill in your credentials. The usual suspects are here Apple, Google, and Facebook:

                      4a10aba7-7cc1-4476-8b35-3f4afca9add3-image.png

                      But there are also some non-public federated logins, if you have one you should know. As explained in my first posting, federated logins are simply not supported by the terminal logins, it cannot deal with the redirects.

                      And as also already stated, please contact end-user-support about any issues you might have with logins, this is simply not an SDK issue.

                      Cheers,
                      Ferdinand

                      MAXON SDK Specialist
                      developers.maxon.net

                      1 Reply Last reply Reply Quote 1
                      • P
                        Peek
                        last edited by

                        @ferdinand

                        Thanks for adding the SDK info and also thanks for the hints, I will investigate further. We normally log in to Maxon accounts via the commandline or via the login window in Cinema, so it should work I imagine.

                        ferdinandF 1 Reply Last reply Reply Quote 0
                        • ferdinandF
                          ferdinand @Peek
                          last edited by ferdinand

                          Hey @Peek,

                          The terminology is here a bit unfortunate, and I was also a bit sloppy with it in my posting (fixed that). Let us make a clear distinction between the 'Commandline' (the Cinema 4D app, not as a term for the shell of an OS) and the terminal or shell of an OS (e.g., CMD. PowerShell on Windows, or just Shell on Mac). If you are already regularly logging in via the shell/terminal, this script should work.

                          But if that would be the case, you probably would not have asked this question, started this topic. As I said, I would just try to manually login with the command I have shown above. And if that does not work, reach out to our end user support. I would also remind you to what I pointed out in the script:

                          Note that Maxon Account as a login model has been deprecated in 2024. e, Google, or Facebook. In the GUI of the Cinema 4D license manager it has been removed altogether, in the terminal it is still available.

                          For federated accounts the terminal login never worked, but maybe they have added more restrictions since 2023.2, blocked certain IP ranges or god knows what else. End user support can help you here ๐Ÿ™‚

                          Cheers,
                          Ferdinand

                          MAXON SDK Specialist
                          developers.maxon.net

                          1 Reply Last reply Reply Quote 1
                          • P
                            Peek
                            last edited by Peek

                            @ferdinand When I was talking about Commandline I mean the actual Cinema4D app/.exe, not the terminal/powershell.

                            I will give the command a go Today and see how it goes. Thanks for the help regardless that it was outside of scope ๐Ÿ™‚

                            Well, with your command on MacOS I basically get a wall of text but it does finish. However when I then manually run the C4D commandline again I get the standard "Enter the license method:" window

                            When I run it in c4dpy it ends on "Welcome to the world of C4D and python (....)" and >>>.

                            Cheers,

                            ferdinandF 1 Reply Last reply Reply Quote 0
                            • ferdinandF
                              ferdinand @Peek
                              last edited by

                              Hey @Peek,

                              when the command does fail for you, this probably means that there is either something wrong with your account/credentials or that the terminal login is broken for the Commandline app on MacOS. I find it a bit odd that you seem to indicate that the login works for the c4dpy app on MacOs but for the Commandline app it does not.

                              This is how it will look like when you try to login with a federated account and the terminal login then failing:

                              527c1428-cfaa-44fc-855c-f46b15f3441f-image.png

                              You should reach out to user support ๐Ÿ™‚

                              Cheers,
                              Ferdinand

                              MAXON SDK Specialist
                              developers.maxon.net

                              1 Reply Last reply Reply Quote 0
                              • P
                                Peek
                                last edited by Peek

                                @ferdinand : Yeah I will because that is definitely not what I'm seeing ๐Ÿ™‚

                                Manually login in in both commandline/c4dpy works. As that is what we are doing now on all render nodes when the licenses vanish yet again.

                                Thanks!

                                1 Reply Last reply Reply Quote 0
                                • ferdinandF
                                  ferdinand
                                  last edited by ferdinand

                                  One last thing: Have you tried using LICENSEMODEL::MAXONAPP as an alternative login method? ::MAXONACCOUNT is being deprecated as I said, and I do not quite remember why we chose it here nonetheless. User support surely can help you with the details here.

                                  MAXON SDK Specialist
                                  developers.maxon.net

                                  1 Reply Last reply Reply Quote 0
                                  • First post
                                    Last post