There is a need to extend memberdata on Plone 4 with certain schema and at the same time provide an efficient (that is, much better than linear) search among those profiles.
collective.examples.userdata seems to be an example on how to make userdata The Right Way, but what about searches? Are there any efficient search solutions, for example, using the catalog?
There is such thing as membrane, which can map users to content, but uses
Archetypes and quite old a product (maybe, my impression is wrong).
Still, for example, mapping userdata to Dexterity type instances could be fine.
The question is, is there any ready code out there or custom solution will be needed?
No, the only ready solution out there, as you said, is membrane. But IMO it's a complex and specific product so I don't think you really need it.
To reach your goal, you'll need a bit of development. More or less the way would be:
insert your users into the catalog
add all needed new indexes
create your custom search form with z3c.form
This is an overview (not detailed howto) of an implementation:
Catalog tool done similarly to the reference_catalog from Archetypes. The most essential parts:
from Products.ZCatalog.ZCatalog import ZCatalog
class MemberdataCatalog(UniqueObject, ZCatalog):
implements(IMemberdataCatalog)
...
security.declareProtected(ManageZCatalogEntries, 'catalog_object')
def catalog_object(self, obj, uid=None, idxs=[],
update_metadata=1, pghandler=None):
w = obj
if not IIndexableObject.providedBy(obj):
wrapper = component.queryMultiAdapter((obj, self), IIndexableObject)
if wrapper is not None:
w = wrapper
ZCatalog.catalog_object(self, w, w and str("/".join(w.getPhysicalPath())), idxs,
update_metadata, pghandler=pghandler)
(with all GenericSetup things, also can be done similarly to Archetypes)
Subscribers for IPrincipalCreatedEvent, IPrincipalDeletedEvent, IConfigurationChangedEvent
(the latter one needs event.context.class._name_ in ('UserDataConfiglet', 'PersonalPreferencesPanel', 'UserDataPanel') to be handled - unfortunately, Plone has no specific events for profile data changes). See PAS on how those work and which parameters
event handlers receive.
A view /memberdata/username for the catalog to address and reindex those users. The "username" done by bobo traverse and returns an wrapped user with properties,
needed for indexes and metadata.
The http://plone.org/products/collective.examples.userdata is a good guide how to actually extend the user profile.
Apart from that, an adapter is needed
class IndexableAdapter(EnhancedUserDataPanelAdapter):
implements(IIndexableObject)
adapts(IMemberData, IMemberdataCatalog)
def __init__(self, context, catalog):
self.context = context
self.userid = context.getId()
self.catalog = catalog
def getPhysicalPath(self):
return make_physical_path(self.userid) # path to the view, which "fakes" an object
def __getattr__(self, name):
""" Proxing attribute accesses. """
return getattr(self.context, name)
# Specific indexer
def SearchableTextIntra(self):
...
Here EnhancedUserDataPanelAdapter has been derived and extended from UserDataPanelAdapter.
The IMemberdataCatalog is the interface of the catalog.
It is important to put everything into metadata, even width/height of the portrait,
because using .getObject() made the whole thing hundreds of times (!) slower.
The group memberships were handled separately, because there are no events, which
signify changes in the groups, needed to reindex some or all memebrs.
Related
I've built a class to ask a user a question, based on a type.
class Question:
def __init__(self, subject):
self.subject = subject
self.question = f"Enter the {subject} to be created. You may end this by typing 'DONE':\n"
self.still_needed = True
def ask_question(self):
ans_list = []
running = True
while running:
var = input(f"Enter {self.subject}?\n")
if var.lower() == 'done':
running = False
else:
ans_list.append(var)
return ans_list
The idea is to have a question model, to create lists of items.
This seems to work well with the following code in main.
roles = Question(subject="role").ask_question()
This creates a list from the Queue Class and uses it's method ask question to generate the list. As far as I can tell the object is then destroyed, as it's not saved to a variable.
My question, being new to Python and OOP is, does this seem like a solid and non-confusing way, or should I refractor? If so, what does the community suggest?
MY OPINION
I guess it depends on you. For one, one of the main purposes of using a class is to create an instance with it later on. Classes are objects ,or "categories" as I like to call them, that you use when there are distinctive types of instances in your project.
Given your code snippet, I can't really suggest anything, I don't know the usage of self.question and self.still_needed. However, if I were to base my opinion on just this part: roles = Question(subject="role").ask_question(), then I'd definitely go with using a function instead. As you've said,
As far as I can tell the object is then destroyed, as it's not saved
to a variable.
ALTERNATIVE SOLUTION
Use decorators → the one with # symbol
In this case, #staticmethod is the way to go!
What are staticmethods? The staticmethod decorator is a way to create a function in a class. So instead of it becoming a method, it can be treated as a function (without self parameter). This also means that a static method bounds to the class rather than its object. Consequently, static methods do not depend on objects (hence, you don't need to create an object for you to use it). Example:
class SomeMathStuff():
#staticmethod
def AddSomeNumbers(iterable):
return sum(iterable)
result = SomeMathStuff.AddSomeNumbers([1, 2, 3])
# result = 6
As you can see, I did not need to create an object, instead I just needed to call its class to use it. Word of warning, most Python programmers argue that this is the un-Pythonic way, but I wouldn't worry too much about it. Hell, even I use these methods sometimes. In my defense, this is a good and efficient way to organize your project. With this, you can apply class methods globally and you can "categorize" them in certain classes you find suitable.
Anyway, this is all I have! I apologize if I misinformed you in any way.
ADDITIONAL INFROMATION ... in case I wasn't the best teacher
https://www.programiz.com/python-programming/methods/built-in/staticmethod
Difference between staticmethod and classmethod
https://softwareengineering.stackexchange.com/questions/171296/staticmethod-vs-module-level-function
As stated in the title, how? I'm really struggling with understanding the documentation as there are no examples of anything. How do I define something like a VoiceState, Member, VoiceChannel, etc...
Running on tutorials is fine until you have to start consulting the documentation for something specific, at which point it becomes really frustrating when you have no idea how to define objects or use certain commands...
A lot of this will come from experience, so don't be discouraged if it takes a while to get the hang of! I know that the docs can be a bit daunting, but I'll try to help as best I can by giving a couple of examples.
When making a discord bot, usually you're going to be getting information based off of arguments and ctx (context).
First I'll start off with some general examples, and then I'll move onto how to use these when working with d.py.
Parameters and args
When you create functions in python, you can define parameter types:
def my_func(a: int):
return a + 5
What this does is assume that the args passed into my_func will be integers, and therefore behave as ints too:
my_func(1)
Will return, as you might expect, 6.
However, when you try to pass in something like so:
my_func("1")
You'll get a TypeError which complains about concatenating str and int. Additionally, you can see the differences in an object when you list its attributes like so: dir(obj)
When applying this same concept to a command:
#bot.command()
async def cmd(ctx, member: discord.Member):
await ctx.send(f"Hello, {member.mention}!")
But when using commands, what it does is it's able to get a member based off of an attribute you enter, such as the member's ID or name. The member that it finds, then has all of the discord.Member object's attributes.
This means you'll be able to access things such as the member's roles, which return a list containing each role as a discord.Role object, which from there, you can get the role's attributes, and so on and so forth.
SIDE-NOTE:
Another way of getting objects in d.py is by using discord.utils. It takes in an iterable, e.g. a list, as the first argument, and then after that it takes keyword arguments, such as name, id, colour, or any attributes of an abc to return an object.
Example:
#bot.command()
async def getrole(ctx):
role = discord.utils.get(ctx.author.roles, name="Very Special Role!", mentionable=True)
await ctx.send(f"Look at you with your {role.mention} How classy!")
And that will iterate through each of the message sender's roles, looking for the name (case sensitive) Very Special Role! which is mentionable, and it will send the message using one of the role's attributes; mention.
Context
With commands, the first argument you're going to be passing in is Context, which by convention is denoted as ctx.
As shown in the link, it has a range of attributes, which revolve mostly around the command's origin, author, and all other details about it etc.
#bot.command()
async def hello(ctx):
await ctx.send(f"Hello, {ctx.author.name}!")
In the command there, I'm using the coroutine from context called send(), which is used for sending messages.
And in the context of the command, it'll be sending it to the same channel, which is how that works.
Also, an example of some commonly used superfluous code:
ctx.message.channel.send("some message")
ctx.message.author.send("some dm")
can be respectively turned into:
ctx.send("some message")
ctx.author.send("some dm")
But how do you know where you can send() a message to? Well that brings us onto the next part:
Abstract Base Classes
These are, what I'm assuming you were talking about when you were on about defining objects. They are the base templates for objects to inherit from - for example, TextChannel has inherited all of Messageable's attributes (except connectable, which is only inherited by discord.VoiceChannel.channel.
I'll use abc.Messageable as an example. In the link, it gives us examples of some Messageable objects, i.e. where you can send messages to, and these are objects such as TextChannels, Members etc.
Occasionally I see someone miss out an await or not know when to add them, or add them too often. You'll know when to add one, as the docs will state whether the function is a couroutine or not, for example:
That's how you know what you can do with each object - think of these as templates for the objects you get within discord, not something that you define!
If you need any further clarification or if you noticed any mistakes with my answer, please let me know.
References:
commands.Command() - decorator for commands
commands.Context
Coroutines
discord.Member
Member.roles
discord.Role
Context.send()
discord.TextChannel
discord.utils
discord.abc
I am building a Python application which calculates sales, stock available and parts required which first asks a user to choose their department from a combobox.
What design should I use to best inform all classes within the application of the choice of department? Once the department is chosen it remains used throughout the application and for the lifecycle of the application instance.
class Sales:
def __init__(self, departmentname):
self.departmentname = departmentname
self.conn = pyodbc.connect(jsonhandler.get_json('connections.json'))
def calculate_sales(self):
with self.conn:
departmentsalesvalues = pd.read_sql_query(f"""SELECT productcode, quantity, salesprice
FROM salestable
WHERE department = ?""", self.conn,
params=(self.departmentname))
return departmentsalesvalues
This works but it seems clumsy/a poor design. I believe I am missing a concept/pattern which would be useful in all programming languages. Can someone point me in the right direction please?
The questions I have asked myself:
Should I create a Department class? But because the department is not similar to the other classes in any way inheritance seems to be out of the question.
Should I pass this information around in a Main/App class? (Which is what i am currently doing.)
Should I have an 'orchestrator' class which interfaces with the Main/App class?
I am quite new to building scalable applications but I find this sort of design question occurring more and more in my projects.
For a variable that is used everywhere and for the life of the application I see two ways that will accomplish the task.
A) Create a global variable (I know.. globals variables are bad. But for this particular scenario, when all you need is the department and you need it everywhere, a global variable is better than rewriting all of your classes to accept a constructor value)
B) Create a 'Context' class that has the department choice as a variable. The context item gets passed to all of your functions when they are called and you can add more information to the context class if need be.
For scalable applications, you would store this information in a 'configuration' file or in a special table in the database.
You would then have context and middleware.
Context is a dictionary that is passed to all of your business functions.
Middleware is a list of classes that alter the context in some way.
You would have a middleware class called "UserChoices" that has a function:
def alterContext(context={}):
context["DepartmentChoice"] = readDBvalue()
return context
Then you would get the context like so
def getContext():
context ={}
for m in middlewares:
context = m(context)
return context
And then you can use your business functions like so
def businessFunc(context):
return stuff
businessFunc(getContext())
I have a poly actor which has a vtkBoxWidget that is connected to a callback as from the example in the docs:
def widget_callback(obj, event):
t = vtk.vtkTransform()
obj.GetTransform(t)
obj.GetProp3D().SetUserTransform(t)
All works fine and I am able to move and transform the actor with the widget but the transformation is applied to the UserTransform and not processed down to the actor properties.
So if I call:
actor.GetPosition()
It returns the initial position prior to making the changes with the widget. And if I call:
actor.GetUserTransform().GetPosition()
I get the updated position relative to the starting point of the first interaction.
Do I have to connect it all through a vtkTransformPolyDataFilter and then update the input connection to the mapper and also calculate the coordinate space offset or is there a simpler way of doing it? ... in short:
What is the correct way of updating an actor with changes applied to SetUserTransform?
After trying out many variations with vtkTransformPolyDataFilter and start/end interaction events linked to various steps in the process I found that for my purpose the absolute simplest way of handling this was simply linking the widget transformation directly to the actor properties:
def widget_callback(self, obj, event):
t = vtk.vtkTransform()
obj.GetTransform(t)
self.actor.SetPosition(t.GetPosition())
self.actor.SetScale(t.GetScale())
self.actor.SetOrientation(t.GetOrientation())
I've a set of concepts that represent types of entities
Hrrr.
Sample concepts:
Loop with children loopCount: IntegerProperty[1]
HttpRequest with children url: StringProperty[1], hostName: StringProperty[1]
Both concepts extend AbstractTestElement concept (it defines common properties like name, comment, etc).
I want Loop and HttpRequest to be generated to baseLanguage as follows:
Loop:
Loop e = new Loop();
e.setProperty(new IntegerProperty("loopCount", node.loopCount));
HttpRequest:
HttpRequest e = new HttpRequest();
e.setProperty(new StringProperty("url", node.url));
e.setProperty(new IntegerProperty("host", node.hostName));
What I want is to have some common generator template that covers this common logic for setProperty so it is not repeated for different kinds of test elements.
Well, there are properties that require specific-to-test-element treatment, however there are often cases when properties are one-to-one translated, thus
Here's the question: how can I attach metadata to the Loop/HttpRequest concept configuration?
What is MPS-idiomatic way of doing that?
1) While I could use "names of properties" as names put into the new XXXProperty, however ideally I would use HttpRequest.HOST_PROPERTY_NAME kind of references, thus "names of properties" is not sufficient.
2) I might probably invent annotations and annotate properties of my concepts, it looks like MPS itself does not use that approach.
3) (ab)using concept's behaviors to return <quotation new StringProperty("url", node.url) > looks even more awkward.
I would rather not use 2. and 3. because both approaches add generator behavior into aspects of your languages which aren't aware of the fact how things will be generated. It basically tight couples you structure with your generator.
If you go for 1, you can still use that static class approach. By creating a new rootnode in the generator which is a java class and contains all your fields. And then have generic generator template that reduces the IntegerProperty and so on ... If they have a common super concept it should be fairly easy to do. You just have to make sure that the property is generated before the containing concept. That way you can still access the role of it in the parent and use that information to generate the field access.