首页 \ 问答 \ Python - 相对导入(Python - Relative import)

Python - 相对导入(Python - Relative import)

我正在开发一个Python程序,它管理和运行模块(.py python文件),这些模块可以由用户添加并通过import函数导入主程序(foo.py)。 这是目录结构

Foo/
    foo.py #Main script. Imports ouput.py, core.py and bar.py when needed.
    src/
        __init__.py
        output.py #Output functions required by bar.py and foo.py
        core.py
    modules/
        __init__.py
        bar.py #Needs output.py

我可以通过使用导入foo.py

from src.output import *

但我遇到的问题是,当我尝试使用时从bar.py导入output.py

from ..src.output import *

我收到了错误

ValueError: Attempted relative import beyond toplevel package

我将文件放在不同的目录中,因为它使不同的程序员更容易分开编码,我肯定需要一个文件夹'modules'或者可以添加.py模块文件的东西,并且它的功能可以在bar.py中使用

如果我做错了,请告诉我。 并随意提出一个更好的方法来做到这一点。

谢谢。


I am developing a Python program where it manages and runs modules ( .py python files ) which can be added by users and are imported into the main program ( foo.py ) by using import function. Here's the directory structure

Foo/
    foo.py #Main script. Imports ouput.py, core.py and bar.py when needed.
    src/
        __init__.py
        output.py #Output functions required by bar.py and foo.py
        core.py
    modules/
        __init__.py
        bar.py #Needs output.py

I can import in foo.py by using

from src.output import *

But the problem I face is that when I try to import output.py from bar.py by using

from ..src.output import *

I get the error

ValueError: Attempted relative import beyond toplevel package

I am putting the files in different directories as it makes it easier for different programmers to code it separately and I definitely need a folder 'modules' or something where .py module files can be added and its functionality be used in bar.py

And please tell me if I am doing this wrong. And feel free to suggest a better way to do it.

Thank You.


原文:https://stackoverflow.com/questions/16254773
更新时间:2022-06-21 06:06

最满意答案

更新:

感谢您的澄清,我更了解您的目标。 您希望从IParameterInspector实现记录的消息反映“Example.MyService.GetContacts”的调用站点,其中Example.MyService是您的服务(由instanceType参数指示),“GetContacts”是操作。 您可以手动合成呼叫站点信息。 你仍然会使用NLog的Logger.Log方法,你仍然可以创建一个LogEventInfo对象。 此外,您可以在LogEventInfo.Properties对象中存储“class”和“method”。 而不是基于instanceType(即服务)检索记录器(来自LogManager),而不是根据参数检查器的类型(在您的情况下为NLogLogger)检索记录器。 最后,您可以向NLog.config添加其他规则(并将其应用于NLogLogger类型),以便该规则具有不同的日志记录格式。 您将手动将包含调用站点信息(存储在LogEventInfo.Properties集合中)的日志记录格式的字段添加到与其他日志记录规则配置中的“真实”调用点LayoutRenderer相同的位置。

接下来,我将发布一个新版本的NLogLogger实现,它完成了我上面描述的内容。

public class NLogLogger : IParameterInspector
{
    private static readonly NLog.Logger logger = LogManager.GetCurrentClassLogger();

    private void Log(Type instanceType, string operationName, string msg)
    {
        NLog.Logger serviceLogger = LogManager.GetLogger(
            instanceType.FullName, instanceType);

        //Create LogEventInfo with the Logger.Name from the logger associated with the service
        LogEventInfo le = new LogEventInfo(LogLevel.Info, serviceLogger.Name, msg);
        le.Properties.Add("fakecallsite", string.Format("{0}.{1}",instanceType.ToString(),operationName);

        //Log the message using the parameter inspector's logger.
        logger.Log(typeof(NLogLogger), le);
    }

    public object BeforeCall(string operationName, object[] inputs)
    {
        // Retrieve the service instance type for the logger then log the call.
        OperationContext operationContext = OperationContext.Current;
        Type instanceType = operationContext.InstanceContext
            .GetServiceInstance().GetType();
        Log(instanceType, operationName, "BeforeCall");

        return instanceType;
    }

    public void AfterCall(
        string operationName, object[] outputs,
        object returnValue, object correlationState
    )
    {
        if (correlationState is Type)
            Log(correlationState, operationName, "AfterCall");
    }
}

您的NLog.config将具有类似的规则。 一条规则专门针对您的NLogLogger参数检查器。 它记录到“f1”并且是“最终”规则,这意味着来自参数检查器的记录消息不会被任何其他规则记录。 另一个规则适用于所有其他记录器。 每个都记录到不同的文件目标,但两个文件目标都写入同一个文件(我认为这是有效的)。 关键是每个文件都有自己的布局。

<logger name="Your.Full.NameSpace.NLogLogger" minlevel="*" writeTo="f1" final="true" /> 
<logger name="*" minlevel="*" writeTo="f2" /> 

你的目标和布局看起来像这样。 我们正在定义一个变量,其值是EventPropertiesLayoutRenderer的值,它是我们存储在LogEventInfo.Properties [“fakecallsite”]中的虚假调用站点。

  <variable name="fakecallsite" value="${event-properties:fakecallsite}"/>
  <variable name="f1layout" value="${longdate} | ${level} | ${logger} | ${fakecallsite} | ${message}"/>
  <variable name="f2layout" value="${longdate} | ${level} | ${logger} | ${callsite} | ${message}"/>
  <targets>
    <target name="f1" xsi:type="File" layout="${f1layout}" fileName="${basedir}/${shortdate}.log" />
    <target name="f2" xsi:type="File" layout="${f2layout}" fileName="${basedir}/${shortdate}.log"        />
  </targets>

请注意,我没有尝试过这个,但我认为它应该可以工作(或者应该足够接近,你可以使它工作)。 一个限制是,由于我们正在计算虚假呼叫站点,我们不能使用真实的呼叫站点LayoutRenderer来操纵输出中的fakecallsite字段的内容。 如果这很重要,可以通过单独存储类和方法(在LogEventInfo.Properties中)然后在NLog.config中设置“fakecallsite”变量来包含类,方法或两者来模拟它。

结束更新

您的包装器应该使用Log方法。 此外,传递给NLog Logger.Log方法的类型应该是NLog Logger包装器的类型,而不是服务实例类型的类型。 您仍然可以使用服务实例的类型来检索正确的Logger实例。 它应该看起来像这样:

public class NLogLogger : IParameterInspector
{
    private void Log(Type instanceType, string operationName, string msg)
    {
        NLog.Logger logger = LogManager.GetLogger(
            instanceType.FullName, instanceType);

        //This is the key to preserving the call site in a wrapper.  Create a LogEventInfo
        //then use NLog's Logger.Log method to log the message, passing the type of your 
        //wrapper as the first argument.

        LogEventInfo le = new LogEventInfo(LogLevel.Info, logger.Name, msg);
        logger.Log(typeof(NLogLogger), le);
    }

    public object BeforeCall(string operationName, object[] inputs)
    {
        // Retrieve the service instance type for the logger then log the call.
        OperationContext operationContext = OperationContext.Current;
        Type instanceType = operationContext.InstanceContext
            .GetServiceInstance().GetType();
        Log(instanceType, operationName, "BeforeCall");

        return instanceType;
    }

    public void AfterCall(
        string operationName, object[] outputs,
        object returnValue, object correlationState
    )
    {
        if (correlationState is Type)
            Log(correlationState, operationName, "AfterCall");
    }
}

UPDATE:

Thanks to your clarification, I better understand what you are trying to do. You would like the messages logged from the IParameterInspector implementation to reflect a call site of "Example.MyService.GetContacts" where Example.MyService is your service (as indicated by the instanceType parameter) and "GetContacts" is the operation. You could synthesize the call site information manually. You would still use NLog's Logger.Log method and you would still create a LogEventInfo object. Additionally, you can store the "class" and "method" in the LogEventInfo.Properties object. Rather than retrieving a logger (from LogManager) based on the instanceType (i.e. the service), retrieve the logger based on the type of the parameter inspector (NLogLogger in your case). Finally, you can add an additional rule to your NLog.config (and apply it to the NLogLogger type) so that rule has a different logging format. You will manually add a field to the logging format that contains the call site information (that you stored in the LogEventInfo.Properties collection) in the same position as the "real" callsite LayoutRenderer in your other logging rule configurations.

Next I will post a new version of your NLogLogger implementation that does what I described above.

public class NLogLogger : IParameterInspector
{
    private static readonly NLog.Logger logger = LogManager.GetCurrentClassLogger();

    private void Log(Type instanceType, string operationName, string msg)
    {
        NLog.Logger serviceLogger = LogManager.GetLogger(
            instanceType.FullName, instanceType);

        //Create LogEventInfo with the Logger.Name from the logger associated with the service
        LogEventInfo le = new LogEventInfo(LogLevel.Info, serviceLogger.Name, msg);
        le.Properties.Add("fakecallsite", string.Format("{0}.{1}",instanceType.ToString(),operationName);

        //Log the message using the parameter inspector's logger.
        logger.Log(typeof(NLogLogger), le);
    }

    public object BeforeCall(string operationName, object[] inputs)
    {
        // Retrieve the service instance type for the logger then log the call.
        OperationContext operationContext = OperationContext.Current;
        Type instanceType = operationContext.InstanceContext
            .GetServiceInstance().GetType();
        Log(instanceType, operationName, "BeforeCall");

        return instanceType;
    }

    public void AfterCall(
        string operationName, object[] outputs,
        object returnValue, object correlationState
    )
    {
        if (correlationState is Type)
            Log(correlationState, operationName, "AfterCall");
    }
}

Your NLog.config will have rules something like this. One rule is specifically for your NLogLogger Parameter Inspector. It logs to "f1" and is a "final" rule, meaning that logging messages from the parameter inspector won't be logged by any other rules. The other rule is for all other loggers. Each logs to a different file target, but both file targets write to the same file (which works, I think). The key is that each file has its own layout.

<logger name="Your.Full.NameSpace.NLogLogger" minlevel="*" writeTo="f1" final="true" /> 
<logger name="*" minlevel="*" writeTo="f2" /> 

Your targets and layouts would look something like this. We are defining a variable whose value is the value of the EventPropertiesLayoutRenderer, which is the fake call site that we stored in LogEventInfo.Properties["fakecallsite"].

  <variable name="fakecallsite" value="${event-properties:fakecallsite}"/>
  <variable name="f1layout" value="${longdate} | ${level} | ${logger} | ${fakecallsite} | ${message}"/>
  <variable name="f2layout" value="${longdate} | ${level} | ${logger} | ${callsite} | ${message}"/>
  <targets>
    <target name="f1" xsi:type="File" layout="${f1layout}" fileName="${basedir}/${shortdate}.log" />
    <target name="f2" xsi:type="File" layout="${f2layout}" fileName="${basedir}/${shortdate}.log"        />
  </targets>

Note that I have not tried this, but I think it should work (or should be close enough that you can get it working). One limitation is that, since we are calculating the fake call site, we cannot use the real callsite LayoutRenderer to manipulate the contents of the fakecallsite field in the output. If this important, it can probably be simulated by storing the class and method separately (in LogEventInfo.Properties) and then setting the "fakecallsite" variable in the NLog.config to contain the class, the method, or both.

END UPDATE

Your wrapper should use the Log method. Also, the type you pass to the NLog Logger.Log method should be the type of your NLog Logger wrapper, not the type of the type of the service instance. You can still use the type of your service instance to retrieve the right Logger instance. It should look something like this:

public class NLogLogger : IParameterInspector
{
    private void Log(Type instanceType, string operationName, string msg)
    {
        NLog.Logger logger = LogManager.GetLogger(
            instanceType.FullName, instanceType);

        //This is the key to preserving the call site in a wrapper.  Create a LogEventInfo
        //then use NLog's Logger.Log method to log the message, passing the type of your 
        //wrapper as the first argument.

        LogEventInfo le = new LogEventInfo(LogLevel.Info, logger.Name, msg);
        logger.Log(typeof(NLogLogger), le);
    }

    public object BeforeCall(string operationName, object[] inputs)
    {
        // Retrieve the service instance type for the logger then log the call.
        OperationContext operationContext = OperationContext.Current;
        Type instanceType = operationContext.InstanceContext
            .GetServiceInstance().GetType();
        Log(instanceType, operationName, "BeforeCall");

        return instanceType;
    }

    public void AfterCall(
        string operationName, object[] outputs,
        object returnValue, object correlationState
    )
    {
        if (correlationState is Type)
            Log(correlationState, operationName, "AfterCall");
    }
}

相关问答

更多
  • 在问了这个问题之后,我多次回顾过,在我问这个问题之前,我做了很多搜索。 我试图尝试各种各样的东西,并希望他们可以工作。 我发现我使用的Common.Logging.NLog.NLogLoggerFactoryAdapter使用的是来自Common.Logging.Nlog dll,并且该dll具有对NLog 1.0.0.505 ,该引用使用NLog 1.0.0.505的旧位置类。 我使用NuGet删除了Common.Logging.Nlog软件包,并将app.config文件中的引用更改为:
  • NLog中的规则可以是特定于目标的,也可以写入所有目标。 默认规则不会指定任何目标,因此它们将写入您创建的任何目标。 您还要添加自己的规则,该规则专门针对您的目标而不是其他目标。 因此,双重记录。 您可以删除默认规则以解决问题。 Config.LoggingRules.Clear(); 在添加规则之前。 Rules in NLog can be target specific, or it can write to all targets. The default rule(s) won't have a ...
  • 我刚刚使用Owin + NLog遇到了这个问题,我发现你需要告诉NLog“ 忽略 ”那些日志包装器 ,这可以通过使用LogManager.AddHiddenAssembly来完成,在我的情况下我只需要将它添加到我的Startup类中: LogManager.AddHiddenAssembly(typeof(NLogFactory).Assembly); LogManager.AddHiddenAssembly(typeof(LoggerExtensions).Assembly); 在你的情况下,我认为它应 ...
  • 那很奇怪...... 一位同事让我在没有Common.Logging包装器的情况下直接尝试使用NLog。 我做了,一切都按预期工作。 之后,我构建了代码,并希望重现问题,将其发布在github页面上。 它工作,不再是问题。 我不知道究竟是什么解决了问题,但对于遇到同样问题的每个人:尝试直接使用NLog一次,然后再使用Common.Logging再试一次。 Well that was strange... A colleague asked me to try using NLog directly with ...
  • 得到它了! 做了更好的搜索,发现了这个奇妙的问题和答案: 在包装NLog时如何保留调用点信息您只需将包装类类型传递给“Log”方法即可。 对于任何有兴趣的人来说,这里是我的新包装类。 最后一种方法使用“typeof”的想法。 public static class Logger { private static string _unclassified = "Unclassified"; [Obsolete("Please supply a LoggerName and LoggerLeve ...
  • 问题已得到解决: https : //github.com/NLog/NLog/commit/138fd2ec5d94072a50037a42bc2b84b6910df641 The problem has been resolved: https://github.com/NLog/NLog/commit/138fd2ec5d94072a50037a42bc2b84b6910df641
  • 问题在于asp布局渲染并缺少它们的包。 我还将internalLogging标志设置为无效值。 这些修正解决了这个问题。 The issue was with asp layout renders and missing a package for them. Also i had set the internalLogging flag to an invalid value. These corrections fixed the problem.
  • .NET框架没有提供更多的选项[1]来获取堆栈StackTrace ,而不是直接使用StackTrace类,或者通过Exception或Environment.StackTrace作为字符串,因此NLog可以做的更多。 此外,对于每个进行的日志调用,callstack将(可能)不同。 一个例外是循环内的日志调用。 但即使在这种情况下,也需要一些机制来帮助NLog甚至知道呼叫是从与前一个“相同的位置”进行的。 这只能在(再次)在callstack处查看。 总而言之,我认为NLog必须做到这一点:在每次进行日志 ...
  • 更新: 感谢您的澄清,我更了解您的目标。 您希望从IParameterInspector实现记录的消息反映“Example.MyService.GetContacts”的调用站点,其中Example.MyService是您的服务(由instanceType参数指示),“GetContacts”是操作。 您可以手动合成呼叫站点信息。 你仍然会使用NLog的Logger.Log方法,你仍然可以创建一个LogEventInfo对象。 此外,您可以在LogEventInfo.Properties对象中存储“clas ...
  • 确保控制器具有无参数的公共构造函数。 您收到此错误的原因是: 您没有在Ninject中显式配置控制器 您的配置中存在错误 因为没有显式注册控制器,Ninject将尝试为您创建它,但由于配置中存在问题,它将返回null (由IDependencyResolver协定决定)。 一旦明确注册了所有控制器(您应该始终在容器中显式注册所有根类型),Ninject将抛出一个表达异常,解释配置错误是什么。 明确注册所有根类型还允许您测试DI配置 。 The problem ended up being that I wa ...

相关文章

更多

最新问答

更多
  • 散列包括方法和/或嵌套属性(Hash include methods and/or nested attributes)
  • TensorFlow:基于索引列表创建新张量(TensorFlow: Create a new tensor based on list of indices)
  • 企业安全培训的各项内容
  • 错误:RPC失败;(error: RPC failed; curl transfer closed with outstanding read data remaining)
  • NumPy:将int64值存储在np.array中并使用dtype float64并将其转换回整数是否安全?(NumPy: Is it safe to store an int64 value in an np.array with dtype float64 and later convert it back to integer?)
  • 注销后如何隐藏导航portlet?(How to hide navigation portlet after logout?)
  • 将多个行和可变行移动到列(moving multiple and variable rows to columns)
  • 对setOnInfoWindowClickListener的意图(Intent on setOnInfoWindowClickListener)
  • Angular $资源不会改变方法(Angular $resource doesn't change method)
  • 如何配置Composite C1以将.m和桌面作为同一站点提供服务(How to configure Composite C1 to serve .m and desktop as the same site)
  • 不适用:悬停在悬停时:在元素之前[复制](Don't apply :hover when hovering on :before element [duplicate])
  • Mysql DB单个字段匹配多个其他字段(Mysql DB single field matching to multiple other fields)
  • 产品页面上的Magento Up出售对齐问题(Magento Up sell alignment issue on the products page)
  • 是否可以嵌套hazelcast IMaps?(Is it possible to nest hazelcast IMaps? And whick side effects can I expect? Is it a good Idea anyway?)
  • UIViewAnimationOptionRepeat在两个动画之间暂停(UIViewAnimationOptionRepeat pausing in between two animations)
  • 在x-kendo-template中使用Razor查询(Using Razor query within x-kendo-template)
  • 在BeautifulSoup中替换文本而不转义(Replace text without escaping in BeautifulSoup)
  • 如何在存根或模拟不存在的方法时配置Rspec以引发错误?(How can I configure Rspec to raise error when stubbing or mocking non-existing methods?)
  • asp用javascript(asp with javascript)
  • “%()s”在sql查询中的含义是什么?(What does “%()s” means in sql query?)
  • 如何为其编辑的内容提供自定义UITableViewCell上下文?(How to give a custom UITableViewCell context of what it is editing?)
  • c ++十进制到二进制,然后使用操作,然后回到十进制(c++ Decimal to binary, then use operation, then back to decimal)
  • 以编程方式创建视频?(Create videos programmatically?)
  • 无法在BeautifulSoup中正确解析数据(Unable to parse data correctly in BeautifulSoup)
  • webform和mvc的区别 知乎
  • 如何使用wadl2java生成REST服务模板,其中POST / PUT方法具有参数?(How do you generate REST service template with wadl2java where POST/PUT methods have parameters?)
  • 我无法理解我的travis构建有什么问题(I am having trouble understanding what is wrong with my travis build)
  • iOS9 Scope Bar出现在Search Bar后面或旁边(iOS9 Scope Bar appears either behind or beside Search Bar)
  • 为什么开机慢上面还显示;Inetrnet,Explorer
  • 有关调用远程WCF服务的超时问题(Timeout Question about Invoking a Remote WCF Service)