Reduce boilerplate for logging












2















I read the docs of structlog: Configuration




The goal is to reduce your per-file logging boilerplate to:



from structlog import get_logger
logger = get_logger()



Is there a way to even reduce this to one import line (without ;)?










share|improve this question




















  • 4





    logger = __import__('structlog').get_logger() (but not recommended really)

    – Chris_Rands
    Jan 19 '17 at 11:12











  • @Chris_Rands thank you for your comment. I think this is a valid answer. Yes, I see it like you: I would not recommend this.

    – guettli
    Jan 19 '17 at 12:38











  • You can add logger = get_logger() at the end of structlog.py and then just use from structlog import logger in your script. Quite unconventional but it works.

    – alec_djinn
    Jan 23 '17 at 16:53
















2















I read the docs of structlog: Configuration




The goal is to reduce your per-file logging boilerplate to:



from structlog import get_logger
logger = get_logger()



Is there a way to even reduce this to one import line (without ;)?










share|improve this question




















  • 4





    logger = __import__('structlog').get_logger() (but not recommended really)

    – Chris_Rands
    Jan 19 '17 at 11:12











  • @Chris_Rands thank you for your comment. I think this is a valid answer. Yes, I see it like you: I would not recommend this.

    – guettli
    Jan 19 '17 at 12:38











  • You can add logger = get_logger() at the end of structlog.py and then just use from structlog import logger in your script. Quite unconventional but it works.

    – alec_djinn
    Jan 23 '17 at 16:53














2












2








2








I read the docs of structlog: Configuration




The goal is to reduce your per-file logging boilerplate to:



from structlog import get_logger
logger = get_logger()



Is there a way to even reduce this to one import line (without ;)?










share|improve this question
















I read the docs of structlog: Configuration




The goal is to reduce your per-file logging boilerplate to:



from structlog import get_logger
logger = get_logger()



Is there a way to even reduce this to one import line (without ;)?







python logging structlog






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 26 '18 at 13:13









Joe

31.8k1490107




31.8k1490107










asked Jan 19 '17 at 10:53









guettliguettli

4,10625142288




4,10625142288








  • 4





    logger = __import__('structlog').get_logger() (but not recommended really)

    – Chris_Rands
    Jan 19 '17 at 11:12











  • @Chris_Rands thank you for your comment. I think this is a valid answer. Yes, I see it like you: I would not recommend this.

    – guettli
    Jan 19 '17 at 12:38











  • You can add logger = get_logger() at the end of structlog.py and then just use from structlog import logger in your script. Quite unconventional but it works.

    – alec_djinn
    Jan 23 '17 at 16:53














  • 4





    logger = __import__('structlog').get_logger() (but not recommended really)

    – Chris_Rands
    Jan 19 '17 at 11:12











  • @Chris_Rands thank you for your comment. I think this is a valid answer. Yes, I see it like you: I would not recommend this.

    – guettli
    Jan 19 '17 at 12:38











  • You can add logger = get_logger() at the end of structlog.py and then just use from structlog import logger in your script. Quite unconventional but it works.

    – alec_djinn
    Jan 23 '17 at 16:53








4




4





logger = __import__('structlog').get_logger() (but not recommended really)

– Chris_Rands
Jan 19 '17 at 11:12





logger = __import__('structlog').get_logger() (but not recommended really)

– Chris_Rands
Jan 19 '17 at 11:12













@Chris_Rands thank you for your comment. I think this is a valid answer. Yes, I see it like you: I would not recommend this.

– guettli
Jan 19 '17 at 12:38





@Chris_Rands thank you for your comment. I think this is a valid answer. Yes, I see it like you: I would not recommend this.

– guettli
Jan 19 '17 at 12:38













You can add logger = get_logger() at the end of structlog.py and then just use from structlog import logger in your script. Quite unconventional but it works.

– alec_djinn
Jan 23 '17 at 16:53





You can add logger = get_logger() at the end of structlog.py and then just use from structlog import logger in your script. Quite unconventional but it works.

– alec_djinn
Jan 23 '17 at 16:53












3 Answers
3






active

oldest

votes


















5





+100









It is not possible to perform a call inside of an import statement.



From Python's grammar:



import_stmt: import_name | import_from
import_name: 'import' dotted_as_names
import_from: ('from' (('.' | '...')* dotted_name | ('.' | '...')+)
'import' ('*' | '(' import_as_names ')' | import_as_names))
import_as_name: NAME ['as' NAME]
dotted_as_name: dotted_name ['as' NAME]
import_as_names: import_as_name (',' import_as_name)* [',']
dotted_as_names: dotted_as_name (',' dotted_as_name)*
dotted_name: NAME ('.' NAME)*


The grammar does not specify a form for an import statement where a call is possible. In particular, the only form accepting parentheses is '(' import_as_names ')', where import_as_names is defined as NAME ['as' NAME], while a call to a function requires the use of parameters.



I recommend a thorough reading of the grammar specification for an in-depth understanding.





However, it is possible to accomplish what you are aiming at in one line. Here are three solutions.



The first one is what you mentioned in your question. The second one was evoked by Chris_Rands in comments (and later on in an answer). The third one is basically a cheat, that looks like a one-liner from the main file.



With a semi-colon



from structlog import get_logger; logger = get_logger()


By calling the underlying __import__ function



logger = __import__('structlog').get_logger()


Note that this is not an import statement, since it does not match any specified form of the above abstract.



By using an intermediary file



interface.py



from structlog import get_logger
logger = get_logger()


main.py



from interface import logger


This is more like cheating, but from the point of view of the main file, the import is a single line.



If you pick this method, I strongly recommend to create a fresh file for the interface.py. You could be tempted to add a logger = get_logger() at the end of structlog.py, but you could break the module, the most obvious situation being that some variable called logger already exists.





This said, having your code in two lines is absolutely fine. I understand that one can want to make one-liners as often as possible, since Python is pretty good at it (I won't link my posts about lambda expressions, but you can easily find some examples).



However, get_logger is actually referenced as structlog.get_logger(*args, **kwargs), which means that it can receive arguments to initialize the logger it returns. The way these are used is documented in get_logger's source.



Now, suppose you have to perform some processing to produce these arguments. Your code will look something like:



from structlog import get_logger

args = initialize_args()
kwargs = initialize_kwargs()

logger = get_logger(args, kwargs)


Well, you could still make it into a one-liner... But it would become unnecessarily long, and pretty much unreadable.






share|improve this answer

































    5














    As I mentioned in my comment, to get a one liner, you could use __import__():



    logger = __import__('structlog').get_logger()



    However, as stated in the documentation, using __import__() is not generally recommended:




    Direct use of __import__() is also
    discouraged in favor of importlib.import_module().




    importlib.import_module() requires importing itself, adding another line via import importlib, unless you import importlib via __import__(), which seems like a bad idea.



    Anyway, you don't need __import__() or importlib.import_module() in your case, which are normally used when you are importing dynamically from a variable that stores the module name as a string. I think you should keep the two lines you have, which are concise and readable in my opinion.






    share|improve this answer

































      1














      As stated by others, there is no clean way to do import and function call on the same line. However, there might be a different approach to this problem.



      I assume you want to enforce DRY principle. If this is the case, you can place small file in your code base doing both:



      # mylog.py
      from structlog import get_logger
      logger = get_logger() # or any other logic to get a compatible logger


      Now, in all other places you can simply get logger instance directly:



      from mylog import logger





      share|improve this answer


























        Your Answer






        StackExchange.ifUsing("editor", function () {
        StackExchange.using("externalEditor", function () {
        StackExchange.using("snippets", function () {
        StackExchange.snippets.init();
        });
        });
        }, "code-snippets");

        StackExchange.ready(function() {
        var channelOptions = {
        tags: "".split(" "),
        id: "1"
        };
        initTagRenderer("".split(" "), "".split(" "), channelOptions);

        StackExchange.using("externalEditor", function() {
        // Have to fire editor after snippets, if snippets enabled
        if (StackExchange.settings.snippets.snippetsEnabled) {
        StackExchange.using("snippets", function() {
        createEditor();
        });
        }
        else {
        createEditor();
        }
        });

        function createEditor() {
        StackExchange.prepareEditor({
        heartbeatType: 'answer',
        autoActivateHeartbeat: false,
        convertImagesToLinks: true,
        noModals: true,
        showLowRepImageUploadWarning: true,
        reputationToPostImages: 10,
        bindNavPrevention: true,
        postfix: "",
        imageUploader: {
        brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
        contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
        allowUrls: true
        },
        onDemand: true,
        discardSelector: ".discard-answer"
        ,immediatelyShowMarkdownHelp:true
        });


        }
        });














        draft saved

        draft discarded


















        StackExchange.ready(
        function () {
        StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f41740012%2freduce-boilerplate-for-logging%23new-answer', 'question_page');
        }
        );

        Post as a guest















        Required, but never shown

























        3 Answers
        3






        active

        oldest

        votes








        3 Answers
        3






        active

        oldest

        votes









        active

        oldest

        votes






        active

        oldest

        votes









        5





        +100









        It is not possible to perform a call inside of an import statement.



        From Python's grammar:



        import_stmt: import_name | import_from
        import_name: 'import' dotted_as_names
        import_from: ('from' (('.' | '...')* dotted_name | ('.' | '...')+)
        'import' ('*' | '(' import_as_names ')' | import_as_names))
        import_as_name: NAME ['as' NAME]
        dotted_as_name: dotted_name ['as' NAME]
        import_as_names: import_as_name (',' import_as_name)* [',']
        dotted_as_names: dotted_as_name (',' dotted_as_name)*
        dotted_name: NAME ('.' NAME)*


        The grammar does not specify a form for an import statement where a call is possible. In particular, the only form accepting parentheses is '(' import_as_names ')', where import_as_names is defined as NAME ['as' NAME], while a call to a function requires the use of parameters.



        I recommend a thorough reading of the grammar specification for an in-depth understanding.





        However, it is possible to accomplish what you are aiming at in one line. Here are three solutions.



        The first one is what you mentioned in your question. The second one was evoked by Chris_Rands in comments (and later on in an answer). The third one is basically a cheat, that looks like a one-liner from the main file.



        With a semi-colon



        from structlog import get_logger; logger = get_logger()


        By calling the underlying __import__ function



        logger = __import__('structlog').get_logger()


        Note that this is not an import statement, since it does not match any specified form of the above abstract.



        By using an intermediary file



        interface.py



        from structlog import get_logger
        logger = get_logger()


        main.py



        from interface import logger


        This is more like cheating, but from the point of view of the main file, the import is a single line.



        If you pick this method, I strongly recommend to create a fresh file for the interface.py. You could be tempted to add a logger = get_logger() at the end of structlog.py, but you could break the module, the most obvious situation being that some variable called logger already exists.





        This said, having your code in two lines is absolutely fine. I understand that one can want to make one-liners as often as possible, since Python is pretty good at it (I won't link my posts about lambda expressions, but you can easily find some examples).



        However, get_logger is actually referenced as structlog.get_logger(*args, **kwargs), which means that it can receive arguments to initialize the logger it returns. The way these are used is documented in get_logger's source.



        Now, suppose you have to perform some processing to produce these arguments. Your code will look something like:



        from structlog import get_logger

        args = initialize_args()
        kwargs = initialize_kwargs()

        logger = get_logger(args, kwargs)


        Well, you could still make it into a one-liner... But it would become unnecessarily long, and pretty much unreadable.






        share|improve this answer






























          5





          +100









          It is not possible to perform a call inside of an import statement.



          From Python's grammar:



          import_stmt: import_name | import_from
          import_name: 'import' dotted_as_names
          import_from: ('from' (('.' | '...')* dotted_name | ('.' | '...')+)
          'import' ('*' | '(' import_as_names ')' | import_as_names))
          import_as_name: NAME ['as' NAME]
          dotted_as_name: dotted_name ['as' NAME]
          import_as_names: import_as_name (',' import_as_name)* [',']
          dotted_as_names: dotted_as_name (',' dotted_as_name)*
          dotted_name: NAME ('.' NAME)*


          The grammar does not specify a form for an import statement where a call is possible. In particular, the only form accepting parentheses is '(' import_as_names ')', where import_as_names is defined as NAME ['as' NAME], while a call to a function requires the use of parameters.



          I recommend a thorough reading of the grammar specification for an in-depth understanding.





          However, it is possible to accomplish what you are aiming at in one line. Here are three solutions.



          The first one is what you mentioned in your question. The second one was evoked by Chris_Rands in comments (and later on in an answer). The third one is basically a cheat, that looks like a one-liner from the main file.



          With a semi-colon



          from structlog import get_logger; logger = get_logger()


          By calling the underlying __import__ function



          logger = __import__('structlog').get_logger()


          Note that this is not an import statement, since it does not match any specified form of the above abstract.



          By using an intermediary file



          interface.py



          from structlog import get_logger
          logger = get_logger()


          main.py



          from interface import logger


          This is more like cheating, but from the point of view of the main file, the import is a single line.



          If you pick this method, I strongly recommend to create a fresh file for the interface.py. You could be tempted to add a logger = get_logger() at the end of structlog.py, but you could break the module, the most obvious situation being that some variable called logger already exists.





          This said, having your code in two lines is absolutely fine. I understand that one can want to make one-liners as often as possible, since Python is pretty good at it (I won't link my posts about lambda expressions, but you can easily find some examples).



          However, get_logger is actually referenced as structlog.get_logger(*args, **kwargs), which means that it can receive arguments to initialize the logger it returns. The way these are used is documented in get_logger's source.



          Now, suppose you have to perform some processing to produce these arguments. Your code will look something like:



          from structlog import get_logger

          args = initialize_args()
          kwargs = initialize_kwargs()

          logger = get_logger(args, kwargs)


          Well, you could still make it into a one-liner... But it would become unnecessarily long, and pretty much unreadable.






          share|improve this answer




























            5





            +100







            5





            +100



            5




            +100





            It is not possible to perform a call inside of an import statement.



            From Python's grammar:



            import_stmt: import_name | import_from
            import_name: 'import' dotted_as_names
            import_from: ('from' (('.' | '...')* dotted_name | ('.' | '...')+)
            'import' ('*' | '(' import_as_names ')' | import_as_names))
            import_as_name: NAME ['as' NAME]
            dotted_as_name: dotted_name ['as' NAME]
            import_as_names: import_as_name (',' import_as_name)* [',']
            dotted_as_names: dotted_as_name (',' dotted_as_name)*
            dotted_name: NAME ('.' NAME)*


            The grammar does not specify a form for an import statement where a call is possible. In particular, the only form accepting parentheses is '(' import_as_names ')', where import_as_names is defined as NAME ['as' NAME], while a call to a function requires the use of parameters.



            I recommend a thorough reading of the grammar specification for an in-depth understanding.





            However, it is possible to accomplish what you are aiming at in one line. Here are three solutions.



            The first one is what you mentioned in your question. The second one was evoked by Chris_Rands in comments (and later on in an answer). The third one is basically a cheat, that looks like a one-liner from the main file.



            With a semi-colon



            from structlog import get_logger; logger = get_logger()


            By calling the underlying __import__ function



            logger = __import__('structlog').get_logger()


            Note that this is not an import statement, since it does not match any specified form of the above abstract.



            By using an intermediary file



            interface.py



            from structlog import get_logger
            logger = get_logger()


            main.py



            from interface import logger


            This is more like cheating, but from the point of view of the main file, the import is a single line.



            If you pick this method, I strongly recommend to create a fresh file for the interface.py. You could be tempted to add a logger = get_logger() at the end of structlog.py, but you could break the module, the most obvious situation being that some variable called logger already exists.





            This said, having your code in two lines is absolutely fine. I understand that one can want to make one-liners as often as possible, since Python is pretty good at it (I won't link my posts about lambda expressions, but you can easily find some examples).



            However, get_logger is actually referenced as structlog.get_logger(*args, **kwargs), which means that it can receive arguments to initialize the logger it returns. The way these are used is documented in get_logger's source.



            Now, suppose you have to perform some processing to produce these arguments. Your code will look something like:



            from structlog import get_logger

            args = initialize_args()
            kwargs = initialize_kwargs()

            logger = get_logger(args, kwargs)


            Well, you could still make it into a one-liner... But it would become unnecessarily long, and pretty much unreadable.






            share|improve this answer















            It is not possible to perform a call inside of an import statement.



            From Python's grammar:



            import_stmt: import_name | import_from
            import_name: 'import' dotted_as_names
            import_from: ('from' (('.' | '...')* dotted_name | ('.' | '...')+)
            'import' ('*' | '(' import_as_names ')' | import_as_names))
            import_as_name: NAME ['as' NAME]
            dotted_as_name: dotted_name ['as' NAME]
            import_as_names: import_as_name (',' import_as_name)* [',']
            dotted_as_names: dotted_as_name (',' dotted_as_name)*
            dotted_name: NAME ('.' NAME)*


            The grammar does not specify a form for an import statement where a call is possible. In particular, the only form accepting parentheses is '(' import_as_names ')', where import_as_names is defined as NAME ['as' NAME], while a call to a function requires the use of parameters.



            I recommend a thorough reading of the grammar specification for an in-depth understanding.





            However, it is possible to accomplish what you are aiming at in one line. Here are three solutions.



            The first one is what you mentioned in your question. The second one was evoked by Chris_Rands in comments (and later on in an answer). The third one is basically a cheat, that looks like a one-liner from the main file.



            With a semi-colon



            from structlog import get_logger; logger = get_logger()


            By calling the underlying __import__ function



            logger = __import__('structlog').get_logger()


            Note that this is not an import statement, since it does not match any specified form of the above abstract.



            By using an intermediary file



            interface.py



            from structlog import get_logger
            logger = get_logger()


            main.py



            from interface import logger


            This is more like cheating, but from the point of view of the main file, the import is a single line.



            If you pick this method, I strongly recommend to create a fresh file for the interface.py. You could be tempted to add a logger = get_logger() at the end of structlog.py, but you could break the module, the most obvious situation being that some variable called logger already exists.





            This said, having your code in two lines is absolutely fine. I understand that one can want to make one-liners as often as possible, since Python is pretty good at it (I won't link my posts about lambda expressions, but you can easily find some examples).



            However, get_logger is actually referenced as structlog.get_logger(*args, **kwargs), which means that it can receive arguments to initialize the logger it returns. The way these are used is documented in get_logger's source.



            Now, suppose you have to perform some processing to produce these arguments. Your code will look something like:



            from structlog import get_logger

            args = initialize_args()
            kwargs = initialize_kwargs()

            logger = get_logger(args, kwargs)


            Well, you could still make it into a one-liner... But it would become unnecessarily long, and pretty much unreadable.







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited May 23 '17 at 12:09









            Community

            11




            11










            answered Jan 23 '17 at 13:38









            Right legRight leg

            8,42842450




            8,42842450

























                5














                As I mentioned in my comment, to get a one liner, you could use __import__():



                logger = __import__('structlog').get_logger()



                However, as stated in the documentation, using __import__() is not generally recommended:




                Direct use of __import__() is also
                discouraged in favor of importlib.import_module().




                importlib.import_module() requires importing itself, adding another line via import importlib, unless you import importlib via __import__(), which seems like a bad idea.



                Anyway, you don't need __import__() or importlib.import_module() in your case, which are normally used when you are importing dynamically from a variable that stores the module name as a string. I think you should keep the two lines you have, which are concise and readable in my opinion.






                share|improve this answer






























                  5














                  As I mentioned in my comment, to get a one liner, you could use __import__():



                  logger = __import__('structlog').get_logger()



                  However, as stated in the documentation, using __import__() is not generally recommended:




                  Direct use of __import__() is also
                  discouraged in favor of importlib.import_module().




                  importlib.import_module() requires importing itself, adding another line via import importlib, unless you import importlib via __import__(), which seems like a bad idea.



                  Anyway, you don't need __import__() or importlib.import_module() in your case, which are normally used when you are importing dynamically from a variable that stores the module name as a string. I think you should keep the two lines you have, which are concise and readable in my opinion.






                  share|improve this answer




























                    5












                    5








                    5







                    As I mentioned in my comment, to get a one liner, you could use __import__():



                    logger = __import__('structlog').get_logger()



                    However, as stated in the documentation, using __import__() is not generally recommended:




                    Direct use of __import__() is also
                    discouraged in favor of importlib.import_module().




                    importlib.import_module() requires importing itself, adding another line via import importlib, unless you import importlib via __import__(), which seems like a bad idea.



                    Anyway, you don't need __import__() or importlib.import_module() in your case, which are normally used when you are importing dynamically from a variable that stores the module name as a string. I think you should keep the two lines you have, which are concise and readable in my opinion.






                    share|improve this answer















                    As I mentioned in my comment, to get a one liner, you could use __import__():



                    logger = __import__('structlog').get_logger()



                    However, as stated in the documentation, using __import__() is not generally recommended:




                    Direct use of __import__() is also
                    discouraged in favor of importlib.import_module().




                    importlib.import_module() requires importing itself, adding another line via import importlib, unless you import importlib via __import__(), which seems like a bad idea.



                    Anyway, you don't need __import__() or importlib.import_module() in your case, which are normally used when you are importing dynamically from a variable that stores the module name as a string. I think you should keep the two lines you have, which are concise and readable in my opinion.







                    share|improve this answer














                    share|improve this answer



                    share|improve this answer








                    edited Jan 23 '17 at 15:17

























                    answered Jan 23 '17 at 14:45









                    Chris_RandsChris_Rands

                    17.2k54176




                    17.2k54176























                        1














                        As stated by others, there is no clean way to do import and function call on the same line. However, there might be a different approach to this problem.



                        I assume you want to enforce DRY principle. If this is the case, you can place small file in your code base doing both:



                        # mylog.py
                        from structlog import get_logger
                        logger = get_logger() # or any other logic to get a compatible logger


                        Now, in all other places you can simply get logger instance directly:



                        from mylog import logger





                        share|improve this answer






























                          1














                          As stated by others, there is no clean way to do import and function call on the same line. However, there might be a different approach to this problem.



                          I assume you want to enforce DRY principle. If this is the case, you can place small file in your code base doing both:



                          # mylog.py
                          from structlog import get_logger
                          logger = get_logger() # or any other logic to get a compatible logger


                          Now, in all other places you can simply get logger instance directly:



                          from mylog import logger





                          share|improve this answer




























                            1












                            1








                            1







                            As stated by others, there is no clean way to do import and function call on the same line. However, there might be a different approach to this problem.



                            I assume you want to enforce DRY principle. If this is the case, you can place small file in your code base doing both:



                            # mylog.py
                            from structlog import get_logger
                            logger = get_logger() # or any other logic to get a compatible logger


                            Now, in all other places you can simply get logger instance directly:



                            from mylog import logger





                            share|improve this answer















                            As stated by others, there is no clean way to do import and function call on the same line. However, there might be a different approach to this problem.



                            I assume you want to enforce DRY principle. If this is the case, you can place small file in your code base doing both:



                            # mylog.py
                            from structlog import get_logger
                            logger = get_logger() # or any other logic to get a compatible logger


                            Now, in all other places you can simply get logger instance directly:



                            from mylog import logger






                            share|improve this answer














                            share|improve this answer



                            share|improve this answer








                            edited Jan 30 '17 at 0:33

























                            answered Jan 29 '17 at 18:44









                            MaratMarat

                            4,03811932




                            4,03811932






























                                draft saved

                                draft discarded




















































                                Thanks for contributing an answer to Stack Overflow!


                                • Please be sure to answer the question. Provide details and share your research!

                                But avoid



                                • Asking for help, clarification, or responding to other answers.

                                • Making statements based on opinion; back them up with references or personal experience.


                                To learn more, see our tips on writing great answers.




                                draft saved


                                draft discarded














                                StackExchange.ready(
                                function () {
                                StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f41740012%2freduce-boilerplate-for-logging%23new-answer', 'question_page');
                                }
                                );

                                Post as a guest















                                Required, but never shown





















































                                Required, but never shown














                                Required, but never shown












                                Required, but never shown







                                Required, but never shown

































                                Required, but never shown














                                Required, but never shown












                                Required, but never shown







                                Required, but never shown







                                Popular posts from this blog

                                Costa Masnaga

                                Fotorealismo

                                Sidney Franklin