Automatically create new objects in a Plone Folder, being the ids only sequential numbers - plone

I have the following structure:
/Plone/folder/year/month/day/id
I want to create the last id sequentially in a tool using invokeFactory. I want to have:
/Plone/folder/2011/06/21/1
/Plone/folder/2011/06/21/2
/Plone/folder/2011/06/21/3
/Plone/folder/2011/06/21/4
Instead of:
/Plone/folder/2011/06/21/id-1
/Plone/folder/2011/06/21/id-2
/Plone/folder/2011/06/21/id-3
/Plone/folder/2011/06/21/id-4
...that is automatically done when I try to create an object with the same name in a folder, Plone handles that for me adding a sequential number. I want an efficient way to create objects, but only using a sequential number instead of a name with a sequential number. I can do that getting the total number os items in a folder, but would like to know if there's a better way.
Real life example: http://plone.org/products/collective.captcha/issues/4

If you're creating these objects manually, you can do something like:
brains = context.getFolderContents({'sort_on' : 'id', 'sort_order' : "reverse"})
if len(brains) > 0:
id = str(int(brains[0].id) + 1)
else:
id = '1'
Then you'll have to create the object manually with that id.
If you want this to do done automatically for you when a user creates content, you might want to look into creating a content rule to change the id of the content for you. An example that might help is collective.contentrules.yearmonth

Related

how to get list of Auto-IVC component output names

I'm switching over to using the Auto-IVC component as opposed to the IndepVar component. I'd like to be able to get a list of the promoted output names of the Auto-IVC component, so I can then use them to go and pull the appropriate value out of a configuration file and set the values that way. This will get rid of some boilerplate.
p.model._auto_ivc.list_outputs()
returns an empty list. It seems that p.model__dict__ has this information encoded in it, but I don't know exactly what is going on there so I am wondering if there is an easier way to do it.
To avoid confusion from future readers, I assume you meant that you wanted the promoted input names for the variables connected to the auto_ivc outputs.
We don't have a built-in function to do this, but you could do it with a bit of code like this:
seen = set()
for n in p.model._inputs:
src = p.model.get_source(n)
if src.startswith('_auto_ivc.') and src not in seen:
print(src, p.model._var_allprocs_abs2prom['input'][n])
seen.add(src)
assuming 'p' is the name of your Problem instance.
The code above just prints each auto_ivc output name followed by the promoted input it's connected to.
Here's an example of the output when run on one of our simple test cases:
_auto_ivc.v0 par.x

How to combine many records value into one record

As you can see from the below picture I was able to combine two deals (blocked red) but the output should have one result instead of two. If anyone has any solutions on this please advise.
The red blocked component has more than one record, each record has an amount, the sum of all record amount must be shown in a single row.
record1: Amount:100
record2: Amount:200
record3: Amount:500
Merge of all records is following
record: Amount:800
Is it possible to merge many rows into a single row in integromat?
Based on your screenshot you aggregate an incorrect module. Source module in your aggregator has to be set to a module that generates multiple modules, in your case, it is module 10.
You aggregate module 14 that generates for every input module a single output module, there is nothing to aggregate. Module 10 returns for a single input 2 bundles.
Your case:
/---[6]---([14]---[11 aggregator])---
---[10] multiple output bundles
\---[6]---([14]---[11 aggregator])---
Solution:
/---[6]---[14]---\
---([10] [11 aggregator])--- single output bundle
\---[6]---[14]---/
Your scenario has to look like this (Aggregator: Source module = module no.10):

How to append / add layers to geopackages in PyQGIS

For a project I am creating different layers which should all be written into one geopackage.
I am using QGIS 3.16.1 and the Python console inside QGIS which runs on Python 3.7
I tried many things but cannot figure out how to do this. This is what I used so far.
vl = QgsVectorLayer("Point", "points1", "memory")
vl2 = QgsVectorLayer("Point", "points2", "memory")
pr = vl.dataProvider()
pr.addAttributes([QgsField("DayID", QVariant.Int), QgsField("distance", QVariant.Double)])
vl.updateFields()
f = QgsFeature()
for x in range(len(tag_temp)):
f.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(lon[x],lat[x])))
f.setAttributes([dayID[x], distance[x]])
pr.addFeature(f)
vl.updateExtents()
# I'll do the same for vl2 but with other data
uri ="D:/Documents/QGIS/test.gpkg"
options = QgsVectorFileWriter.SaveVectorOptions()
context = QgsProject.instance().transformContext()
QgsVectorFileWriter.writeAsVectorFormatV2(vl1,uri,context,options)
QgsVectorFileWriter.writeAsVectorFormatV2(vl2,uri,context,options)
Problem is that the in the 'test.gpkg' a layer is created called 'test' and not 'points1' or 'points2'.
And the second QgsVectorFileWriter.writeAsVectorFormatV2() also overwrites the output of the first one instead of appending the layer into the existing geopackage.
I also tried to create single .geopackages and then use 'Package Layers' processing tool (processing.run("native:package") to merge all layers into one geopackage, but then the attributes types are all converted into strings unfortunately.
Any help is much appreciated. Many thanks in advance.
You need to change the SaveVectorOptions, in particular the mode of actionOnExistingFile after creating the gpkg file :
options = QgsVectorFileWriter.SaveVectorOptions()
#options.driverName = "GPKG"
options.layerName = v1.name()
QgsVectorFileWriter.writeAsVectorFormatV2(v1,uri,context,options)
#switch mode to append layer instead of overwriting the file
options.actionOnExistingFile = QgsVectorFileWriter.CreateOrOverwriteLayer
options.layerName = v2.name()
QgsVectorFileWriter.writeAsVectorFormatV2(v2,uri,context,options)
The documentation is here : SaveVectorOptions
I also tried to create single .geopackages and then use 'Package Layers' processing tool (processing.run("native:package") to merge all layers into one geopackage, but then the attributes types are all converted into strings unfortunately.
This is definitively the recommended way, please consider reporting the bug

Nokogiri and isolating select elements from an array full of Nokogiri nodes

I'm trying to scrape http://www.ign.com/games/reviews using Nokogiri and I'd like to instantiate new review objects that correspond to each game review on the page. Naturally, I'd also like to grab each numeric Score from each review and assign that score value as a class attribute to my review objects.
The problem is, the best I can do is return an entire string of scores mushed together instead of a list consisting of each score.
class VideoGameReviews::Review
attr_accessor :name, :score, :url
def self.scrape_titles
#doc = Nokogiri::HTML(open("http://www.ign.com/games/reviews?"))
#doc.search("#item-list div.itemList div.itemList-item").each do |review|
new_review = VideoGameReviews::Review.new
new_review.score = review.search("span.scoreBox-score").text
=> "99996.37.17.17.17778.58.58.586.36.47.187.57.88.95.587.6" #Not what I want
end
end
end
Any advice on how to extract a list of scores with each score separate and unique from other scores? Maybe use a more specific CSS selector?
You are using nokogiri properly but need to revise your logic to store the scores properly. For instance, we can get the score for an individual game pretty easily:
new_review.score = fourth_item.search("span.scoreBox-score").text
=> "6.3"
Instead of having to do everything in a single method, you can start by breaking your code into smaller methods and cacheing values as needed. I would change this class name as well since your Review class both represents a Review item and also scrapes (violation of Single Responsibility Principle). Maybe something like the following would be better?
require ‘nokogiri’
class VideoGameReviews::ReviewScraper
def reviews
#reviews ||= Nokogiri::HTML(open("http://www.ign.com/games/reviews?"))
end
def review_items
#review_items ||= reviews.search("#item-list div.itemList div.itemList-item")
end
def store_reviews
review_items.each do |review|
new_review = VideoGameReviews::Review.new #Review class still used to save review
new_review.score = review.search("span.scoreBox-score").text
#get other data
new_review.save! #or however you plan on persisting the data
end
end
end
The question will be: how will you save the reviews (in local memory, in a db, etc)? For something quick, ActiveRecord is pretty simple (and you use it independently from Rails).
Note that the :each method in Ruby will always return the original collection on which it's called. so for instance the following will return [1,2]:
[1,2].each do |n|
n * 4
end

How to get programatically the file path from a directory parameter in abap?

The transaction AL11 returns a mapping of "directory parameters" to file paths on the application server AFAIK.
The trouble with transaction AL11 is that its program only calls c modules, there's almost no trace of select statements or function calls to analize there.
I want the ability to do this dynamically, in my code, like for instance a function module that took "DATA_DIR" as input and "E:\usr\sap\IDS\DVEBMGS00\data" as output.
This thread is about a similar topic, but it doesn't help.
Some other guy has the same problem, and he explains it quite well here.
I strongly suspect that the only way to get these values is through the kernel directly. some of them can vary depending on the application server, so you probably won't be able to find them in the database. You could try this:
TYPE-POOLS abap.
TYPES: BEGIN OF t_directory,
log_name TYPE dirprofilenames,
phys_path TYPE dirname_al11,
END OF t_directory.
DATA: lt_int_list TYPE TABLE OF abaplist,
lt_string_list TYPE list_string_table,
lt_directories TYPE TABLE OF t_directory,
ls_directory TYPE t_directory.
FIELD-SYMBOLS: <l_line> TYPE string.
START-OF-SELECTION-OR-FORM-OR-METHOD-OR-WHATEVER.
* get the output of the program as string table
SUBMIT rswatch0 EXPORTING LIST TO MEMORY AND RETURN.
CALL FUNCTION 'LIST_FROM_MEMORY'
TABLES
listobject = lt_int_list.
CALL FUNCTION 'LIST_TO_ASCI'
EXPORTING
with_line_break = abap_true
IMPORTING
list_string_ascii = lt_string_list
TABLES
listobject = lt_int_list.
* remove the separators and the two header lines
DELETE lt_string_list WHERE table_line CO '-'.
DELETE lt_string_list INDEX 1.
DELETE lt_string_list INDEX 1.
* parse the individual lines
LOOP AT lt_string_list ASSIGNING <l_line>.
* If you're on a newer system, you can do this in a more elegant way using regular expressions
CONDENSE <l_line>.
SHIFT <l_line> LEFT DELETING LEADING '|'.
SHIFT <l_line> RIGHT DELETING TRAILING '|'.
SPLIT <l_line>+1 AT '|' INTO ls_directory-log_name ls_directory-phys_path.
APPEND ls_directory TO lt_directories.
ENDLOOP.
Try the following
data : dirname type DIRNAME_AL11.
CALL 'C_SAPGPARAM' ID 'NAME' FIELD 'DIR_DATA'
ID 'VALUE' FIELD dirname.
Alternatively if you wanted to use your own parameters(AL11->configure) then read these out of table user_dir.

Resources